Shell not detected, Symfony shell completion only supports "%s").>', implode('", "', $supportedShells)));
+ }
+
+ return 2;
+ }
+
+ $output->write(str_replace(['{{ COMMAND_NAME }}', '{{ VERSION }}'], [$commandName, $this->getApplication()->getVersion()], file_get_contents($completionFile)));
+
+ return 0;
+ }
+
+ private static function guessShell(): string
+ {
+ return basename($_SERVER['SHELL'] ?? '');
+ }
+
+ private function tailDebugLog(string $commandName, OutputInterface $output): void
+ {
+ $debugFile = sys_get_temp_dir().'/sf_'.$commandName.'.log';
+ if (!file_exists($debugFile)) {
+ touch($debugFile);
+ }
+ $process = new Process(['tail', '-f', $debugFile], null, null, null, 0);
+ $process->run(function (string $type, string $line) use ($output): void {
+ $output->write($line);
+ });
+ }
+
+ /**
+ * @return string[]
+ */
+ private function getSupportedShells(): array
+ {
+ $shells = [];
+
+ foreach (new \DirectoryIterator(__DIR__.'/../Resources/') as $file) {
+ if (str_starts_with($file->getBasename(), 'completion.') && $file->isFile()) {
+ $shells[] = $file->getExtension();
+ }
+ }
+
+ return $shells;
+ }
+}
diff --git a/vendor/symfony/console/Command/HelpCommand.php b/vendor/symfony/console/Command/HelpCommand.php
index cece78299..c66ef463e 100644
--- a/vendor/symfony/console/Command/HelpCommand.php
+++ b/vendor/symfony/console/Command/HelpCommand.php
@@ -11,6 +11,9 @@
namespace Symfony\Component\Console\Command;
+use Symfony\Component\Console\Completion\CompletionInput;
+use Symfony\Component\Console\Completion\CompletionSuggestions;
+use Symfony\Component\Console\Descriptor\ApplicationDescription;
use Symfony\Component\Console\Helper\DescriptorHelper;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
@@ -44,11 +47,11 @@ class HelpCommand extends Command
->setHelp(<<<'EOF'
The %command.name% command displays help for a given command:
- php %command.full_name% list
+ %command.full_name% list
You can also output the help in other formats by using the --format option:
- php %command.full_name% --format=xml list
+ %command.full_name% --format=xml list
To display the list of available commands, please use the list command.
EOF
@@ -80,4 +83,19 @@ EOF
return 0;
}
+
+ public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
+ {
+ if ($input->mustSuggestArgumentValuesFor('command_name')) {
+ $descriptor = new ApplicationDescription($this->getApplication());
+ $suggestions->suggestValues(array_keys($descriptor->getCommands()));
+
+ return;
+ }
+
+ if ($input->mustSuggestOptionValuesFor('format')) {
+ $helper = new DescriptorHelper();
+ $suggestions->suggestValues($helper->getFormats());
+ }
+ }
}
diff --git a/vendor/symfony/console/Command/LazyCommand.php b/vendor/symfony/console/Command/LazyCommand.php
new file mode 100644
index 000000000..e576ad03f
--- /dev/null
+++ b/vendor/symfony/console/Command/LazyCommand.php
@@ -0,0 +1,218 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Console\Command;
+
+use Symfony\Component\Console\Application;
+use Symfony\Component\Console\Completion\CompletionInput;
+use Symfony\Component\Console\Completion\CompletionSuggestions;
+use Symfony\Component\Console\Helper\HelperSet;
+use Symfony\Component\Console\Input\InputDefinition;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * @author Nicolas Grekas
+ */
+final class LazyCommand extends Command
+{
+ private $command;
+ private $isEnabled;
+
+ public function __construct(string $name, array $aliases, string $description, bool $isHidden, \Closure $commandFactory, ?bool $isEnabled = true)
+ {
+ $this->setName($name)
+ ->setAliases($aliases)
+ ->setHidden($isHidden)
+ ->setDescription($description);
+
+ $this->command = $commandFactory;
+ $this->isEnabled = $isEnabled;
+ }
+
+ public function ignoreValidationErrors(): void
+ {
+ $this->getCommand()->ignoreValidationErrors();
+ }
+
+ public function setApplication(Application $application = null): void
+ {
+ if ($this->command instanceof parent) {
+ $this->command->setApplication($application);
+ }
+
+ parent::setApplication($application);
+ }
+
+ public function setHelperSet(HelperSet $helperSet): void
+ {
+ if ($this->command instanceof parent) {
+ $this->command->setHelperSet($helperSet);
+ }
+
+ parent::setHelperSet($helperSet);
+ }
+
+ public function isEnabled(): bool
+ {
+ return $this->isEnabled ?? $this->getCommand()->isEnabled();
+ }
+
+ public function run(InputInterface $input, OutputInterface $output): int
+ {
+ return $this->getCommand()->run($input, $output);
+ }
+
+ public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
+ {
+ $this->getCommand()->complete($input, $suggestions);
+ }
+
+ /**
+ * @return $this
+ */
+ public function setCode(callable $code): self
+ {
+ $this->getCommand()->setCode($code);
+
+ return $this;
+ }
+
+ /**
+ * @internal
+ */
+ public function mergeApplicationDefinition(bool $mergeArgs = true): void
+ {
+ $this->getCommand()->mergeApplicationDefinition($mergeArgs);
+ }
+
+ /**
+ * @return $this
+ */
+ public function setDefinition($definition): self
+ {
+ $this->getCommand()->setDefinition($definition);
+
+ return $this;
+ }
+
+ public function getDefinition(): InputDefinition
+ {
+ return $this->getCommand()->getDefinition();
+ }
+
+ public function getNativeDefinition(): InputDefinition
+ {
+ return $this->getCommand()->getNativeDefinition();
+ }
+
+ /**
+ * @return $this
+ */
+ public function addArgument(string $name, int $mode = null, string $description = '', $default = null): self
+ {
+ $this->getCommand()->addArgument($name, $mode, $description, $default);
+
+ return $this;
+ }
+
+ /**
+ * @return $this
+ */
+ public function addOption(string $name, $shortcut = null, int $mode = null, string $description = '', $default = null): self
+ {
+ $this->getCommand()->addOption($name, $shortcut, $mode, $description, $default);
+
+ return $this;
+ }
+
+ /**
+ * @return $this
+ */
+ public function setProcessTitle(string $title): self
+ {
+ $this->getCommand()->setProcessTitle($title);
+
+ return $this;
+ }
+
+ /**
+ * @return $this
+ */
+ public function setHelp(string $help): self
+ {
+ $this->getCommand()->setHelp($help);
+
+ return $this;
+ }
+
+ public function getHelp(): string
+ {
+ return $this->getCommand()->getHelp();
+ }
+
+ public function getProcessedHelp(): string
+ {
+ return $this->getCommand()->getProcessedHelp();
+ }
+
+ public function getSynopsis(bool $short = false): string
+ {
+ return $this->getCommand()->getSynopsis($short);
+ }
+
+ /**
+ * @return $this
+ */
+ public function addUsage(string $usage): self
+ {
+ $this->getCommand()->addUsage($usage);
+
+ return $this;
+ }
+
+ public function getUsages(): array
+ {
+ return $this->getCommand()->getUsages();
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getHelper(string $name)
+ {
+ return $this->getCommand()->getHelper($name);
+ }
+
+ public function getCommand(): parent
+ {
+ if (!$this->command instanceof \Closure) {
+ return $this->command;
+ }
+
+ $command = $this->command = ($this->command)();
+ $command->setApplication($this->getApplication());
+
+ if (null !== $this->getHelperSet()) {
+ $command->setHelperSet($this->getHelperSet());
+ }
+
+ $command->setName($this->getName())
+ ->setAliases($this->getAliases())
+ ->setHidden($this->isHidden())
+ ->setDescription($this->getDescription());
+
+ // Will throw if the command is not correctly initialized.
+ $command->getDefinition();
+
+ return $command;
+ }
+}
diff --git a/vendor/symfony/console/Command/ListCommand.php b/vendor/symfony/console/Command/ListCommand.php
index 44324a5e7..f04a4ef67 100644
--- a/vendor/symfony/console/Command/ListCommand.php
+++ b/vendor/symfony/console/Command/ListCommand.php
@@ -11,9 +11,11 @@
namespace Symfony\Component\Console\Command;
+use Symfony\Component\Console\Completion\CompletionInput;
+use Symfony\Component\Console\Completion\CompletionSuggestions;
+use Symfony\Component\Console\Descriptor\ApplicationDescription;
use Symfony\Component\Console\Helper\DescriptorHelper;
use Symfony\Component\Console\Input\InputArgument;
-use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
@@ -32,37 +34,34 @@ class ListCommand extends Command
{
$this
->setName('list')
- ->setDefinition($this->createDefinition())
+ ->setDefinition([
+ new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'),
+ new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'),
+ new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
+ new InputOption('short', null, InputOption::VALUE_NONE, 'To skip describing commands\' arguments'),
+ ])
->setDescription('List commands')
->setHelp(<<<'EOF'
The %command.name% command lists all commands:
- php %command.full_name%
+ %command.full_name%
You can also display the commands for a specific namespace:
- php %command.full_name% test
+ %command.full_name% test
You can also output the information in other formats by using the --format option:
- php %command.full_name% --format=xml
+ %command.full_name% --format=xml
It's also possible to get raw list of commands (useful for embedding command runner):
- php %command.full_name% --raw
+ %command.full_name% --raw
EOF
)
;
}
- /**
- * {@inheritdoc}
- */
- public function getNativeDefinition()
- {
- return $this->createDefinition();
- }
-
/**
* {@inheritdoc}
*/
@@ -73,17 +72,24 @@ EOF
'format' => $input->getOption('format'),
'raw_text' => $input->getOption('raw'),
'namespace' => $input->getArgument('namespace'),
+ 'short' => $input->getOption('short'),
]);
return 0;
}
- private function createDefinition(): InputDefinition
+ public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
{
- return new InputDefinition([
- new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'),
- new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'),
- new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
- ]);
+ if ($input->mustSuggestArgumentValuesFor('namespace')) {
+ $descriptor = new ApplicationDescription($this->getApplication());
+ $suggestions->suggestValues(array_keys($descriptor->getNamespaces()));
+
+ return;
+ }
+
+ if ($input->mustSuggestOptionValuesFor('format')) {
+ $helper = new DescriptorHelper();
+ $suggestions->suggestValues($helper->getFormats());
+ }
}
}
diff --git a/vendor/symfony/console/Command/LockableTrait.php b/vendor/symfony/console/Command/LockableTrait.php
index 60cfe360f..b1856dca7 100644
--- a/vendor/symfony/console/Command/LockableTrait.php
+++ b/vendor/symfony/console/Command/LockableTrait.php
@@ -12,8 +12,8 @@
namespace Symfony\Component\Console\Command;
use Symfony\Component\Console\Exception\LogicException;
-use Symfony\Component\Lock\Lock;
use Symfony\Component\Lock\LockFactory;
+use Symfony\Component\Lock\LockInterface;
use Symfony\Component\Lock\Store\FlockStore;
use Symfony\Component\Lock\Store\SemaphoreStore;
@@ -24,7 +24,7 @@ use Symfony\Component\Lock\Store\SemaphoreStore;
*/
trait LockableTrait
{
- /** @var Lock */
+ /** @var LockInterface|null */
private $lock;
/**
diff --git a/vendor/symfony/console/Command/SignalableCommandInterface.php b/vendor/symfony/console/Command/SignalableCommandInterface.php
new file mode 100644
index 000000000..d439728b6
--- /dev/null
+++ b/vendor/symfony/console/Command/SignalableCommandInterface.php
@@ -0,0 +1,30 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Console\Command;
+
+/**
+ * Interface for command reacting to signal.
+ *
+ * @author Grégoire Pineau
+ */
+interface SignalableCommandInterface
+{
+ /**
+ * Returns the list of signals to subscribe.
+ */
+ public function getSubscribedSignals(): array;
+
+ /**
+ * The method will be called when the application is signaled.
+ */
+ public function handleSignal(int $signal): void;
+}
diff --git a/vendor/symfony/console/CommandLoader/CommandLoaderInterface.php b/vendor/symfony/console/CommandLoader/CommandLoaderInterface.php
index ca1029cb6..0adaf886f 100644
--- a/vendor/symfony/console/CommandLoader/CommandLoaderInterface.php
+++ b/vendor/symfony/console/CommandLoader/CommandLoaderInterface.php
@@ -22,25 +22,21 @@ interface CommandLoaderInterface
/**
* Loads a command.
*
- * @param string $name
- *
* @return Command
*
* @throws CommandNotFoundException
*/
- public function get($name);
+ public function get(string $name);
/**
* Checks if a command exists.
*
- * @param string $name
- *
* @return bool
*/
- public function has($name);
+ public function has(string $name);
/**
- * @return string[] All registered command names
+ * @return string[]
*/
public function getNames();
}
diff --git a/vendor/symfony/console/CommandLoader/ContainerCommandLoader.php b/vendor/symfony/console/CommandLoader/ContainerCommandLoader.php
index 50e5950a4..ddccb3d45 100644
--- a/vendor/symfony/console/CommandLoader/ContainerCommandLoader.php
+++ b/vendor/symfony/console/CommandLoader/ContainerCommandLoader.php
@@ -36,7 +36,7 @@ class ContainerCommandLoader implements CommandLoaderInterface
/**
* {@inheritdoc}
*/
- public function get($name)
+ public function get(string $name)
{
if (!$this->has($name)) {
throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name));
@@ -48,7 +48,7 @@ class ContainerCommandLoader implements CommandLoaderInterface
/**
* {@inheritdoc}
*/
- public function has($name)
+ public function has(string $name)
{
return isset($this->commandMap[$name]) && $this->container->has($this->commandMap[$name]);
}
diff --git a/vendor/symfony/console/CommandLoader/FactoryCommandLoader.php b/vendor/symfony/console/CommandLoader/FactoryCommandLoader.php
index d9c205571..7e2db3464 100644
--- a/vendor/symfony/console/CommandLoader/FactoryCommandLoader.php
+++ b/vendor/symfony/console/CommandLoader/FactoryCommandLoader.php
@@ -33,7 +33,7 @@ class FactoryCommandLoader implements CommandLoaderInterface
/**
* {@inheritdoc}
*/
- public function has($name)
+ public function has(string $name)
{
return isset($this->factories[$name]);
}
@@ -41,7 +41,7 @@ class FactoryCommandLoader implements CommandLoaderInterface
/**
* {@inheritdoc}
*/
- public function get($name)
+ public function get(string $name)
{
if (!isset($this->factories[$name])) {
throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name));
diff --git a/vendor/symfony/console/Completion/CompletionInput.php b/vendor/symfony/console/Completion/CompletionInput.php
new file mode 100644
index 000000000..368b94507
--- /dev/null
+++ b/vendor/symfony/console/Completion/CompletionInput.php
@@ -0,0 +1,249 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Console\Completion;
+
+use Symfony\Component\Console\Exception\RuntimeException;
+use Symfony\Component\Console\Input\ArgvInput;
+use Symfony\Component\Console\Input\InputDefinition;
+use Symfony\Component\Console\Input\InputOption;
+
+/**
+ * An input specialized for shell completion.
+ *
+ * This input allows unfinished option names or values and exposes what kind of
+ * completion is expected.
+ *
+ * @author Wouter de Jong
+ */
+final class CompletionInput extends ArgvInput
+{
+ public const TYPE_ARGUMENT_VALUE = 'argument_value';
+ public const TYPE_OPTION_VALUE = 'option_value';
+ public const TYPE_OPTION_NAME = 'option_name';
+ public const TYPE_NONE = 'none';
+
+ private $tokens;
+ private $currentIndex;
+ private $completionType;
+ private $completionName = null;
+ private $completionValue = '';
+
+ /**
+ * Converts a terminal string into tokens.
+ *
+ * This is required for shell completions without COMP_WORDS support.
+ */
+ public static function fromString(string $inputStr, int $currentIndex): self
+ {
+ preg_match_all('/(?<=^|\s)([\'"]?)(.+?)(?tokens = $tokens;
+ $input->currentIndex = $currentIndex;
+
+ return $input;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function bind(InputDefinition $definition): void
+ {
+ parent::bind($definition);
+
+ $relevantToken = $this->getRelevantToken();
+ if ('-' === $relevantToken[0]) {
+ // the current token is an input option: complete either option name or option value
+ [$optionToken, $optionValue] = explode('=', $relevantToken, 2) + ['', ''];
+
+ $option = $this->getOptionFromToken($optionToken);
+ if (null === $option && !$this->isCursorFree()) {
+ $this->completionType = self::TYPE_OPTION_NAME;
+ $this->completionValue = $relevantToken;
+
+ return;
+ }
+
+ if (null !== $option && $option->acceptValue()) {
+ $this->completionType = self::TYPE_OPTION_VALUE;
+ $this->completionName = $option->getName();
+ $this->completionValue = $optionValue ?: (!str_starts_with($optionToken, '--') ? substr($optionToken, 2) : '');
+
+ return;
+ }
+ }
+
+ $previousToken = $this->tokens[$this->currentIndex - 1];
+ if ('-' === $previousToken[0] && '' !== trim($previousToken, '-')) {
+ // check if previous option accepted a value
+ $previousOption = $this->getOptionFromToken($previousToken);
+ if (null !== $previousOption && $previousOption->acceptValue()) {
+ $this->completionType = self::TYPE_OPTION_VALUE;
+ $this->completionName = $previousOption->getName();
+ $this->completionValue = $relevantToken;
+
+ return;
+ }
+ }
+
+ // complete argument value
+ $this->completionType = self::TYPE_ARGUMENT_VALUE;
+
+ foreach ($this->definition->getArguments() as $argumentName => $argument) {
+ if (!isset($this->arguments[$argumentName])) {
+ break;
+ }
+
+ $argumentValue = $this->arguments[$argumentName];
+ $this->completionName = $argumentName;
+ if (\is_array($argumentValue)) {
+ $this->completionValue = $argumentValue ? $argumentValue[array_key_last($argumentValue)] : null;
+ } else {
+ $this->completionValue = $argumentValue;
+ }
+ }
+
+ if ($this->currentIndex >= \count($this->tokens)) {
+ if (!isset($this->arguments[$argumentName]) || $this->definition->getArgument($argumentName)->isArray()) {
+ $this->completionName = $argumentName;
+ $this->completionValue = '';
+ } else {
+ // we've reached the end
+ $this->completionType = self::TYPE_NONE;
+ $this->completionName = null;
+ $this->completionValue = '';
+ }
+ }
+ }
+
+ /**
+ * Returns the type of completion required.
+ *
+ * TYPE_ARGUMENT_VALUE when completing the value of an input argument
+ * TYPE_OPTION_VALUE when completing the value of an input option
+ * TYPE_OPTION_NAME when completing the name of an input option
+ * TYPE_NONE when nothing should be completed
+ *
+ * @return string One of self::TYPE_* constants. TYPE_OPTION_NAME and TYPE_NONE are already implemented by the Console component
+ */
+ public function getCompletionType(): string
+ {
+ return $this->completionType;
+ }
+
+ /**
+ * The name of the input option or argument when completing a value.
+ *
+ * @return string|null returns null when completing an option name
+ */
+ public function getCompletionName(): ?string
+ {
+ return $this->completionName;
+ }
+
+ /**
+ * The value already typed by the user (or empty string).
+ */
+ public function getCompletionValue(): string
+ {
+ return $this->completionValue;
+ }
+
+ public function mustSuggestOptionValuesFor(string $optionName): bool
+ {
+ return self::TYPE_OPTION_VALUE === $this->getCompletionType() && $optionName === $this->getCompletionName();
+ }
+
+ public function mustSuggestArgumentValuesFor(string $argumentName): bool
+ {
+ return self::TYPE_ARGUMENT_VALUE === $this->getCompletionType() && $argumentName === $this->getCompletionName();
+ }
+
+ protected function parseToken(string $token, bool $parseOptions): bool
+ {
+ try {
+ return parent::parseToken($token, $parseOptions);
+ } catch (RuntimeException $e) {
+ // suppress errors, completed input is almost never valid
+ }
+
+ return $parseOptions;
+ }
+
+ private function getOptionFromToken(string $optionToken): ?InputOption
+ {
+ $optionName = ltrim($optionToken, '-');
+ if (!$optionName) {
+ return null;
+ }
+
+ if ('-' === ($optionToken[1] ?? ' ')) {
+ // long option name
+ return $this->definition->hasOption($optionName) ? $this->definition->getOption($optionName) : null;
+ }
+
+ // short option name
+ return $this->definition->hasShortcut($optionName[0]) ? $this->definition->getOptionForShortcut($optionName[0]) : null;
+ }
+
+ /**
+ * The token of the cursor, or the last token if the cursor is at the end of the input.
+ */
+ private function getRelevantToken(): string
+ {
+ return $this->tokens[$this->isCursorFree() ? $this->currentIndex - 1 : $this->currentIndex];
+ }
+
+ /**
+ * Whether the cursor is "free" (i.e. at the end of the input preceded by a space).
+ */
+ private function isCursorFree(): bool
+ {
+ $nrOfTokens = \count($this->tokens);
+ if ($this->currentIndex > $nrOfTokens) {
+ throw new \LogicException('Current index is invalid, it must be the number of input tokens or one more.');
+ }
+
+ return $this->currentIndex >= $nrOfTokens;
+ }
+
+ public function __toString()
+ {
+ $str = '';
+ foreach ($this->tokens as $i => $token) {
+ $str .= $token;
+
+ if ($this->currentIndex === $i) {
+ $str .= '|';
+ }
+
+ $str .= ' ';
+ }
+
+ if ($this->currentIndex > $i) {
+ $str .= '|';
+ }
+
+ return rtrim($str);
+ }
+}
diff --git a/vendor/symfony/console/Completion/CompletionSuggestions.php b/vendor/symfony/console/Completion/CompletionSuggestions.php
new file mode 100644
index 000000000..d8905e5ee
--- /dev/null
+++ b/vendor/symfony/console/Completion/CompletionSuggestions.php
@@ -0,0 +1,99 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Console\Completion;
+
+use Symfony\Component\Console\Input\InputOption;
+
+/**
+ * Stores all completion suggestions for the current input.
+ *
+ * @author Wouter de Jong
+ */
+final class CompletionSuggestions
+{
+ private $valueSuggestions = [];
+ private $optionSuggestions = [];
+
+ /**
+ * Add a suggested value for an input option or argument.
+ *
+ * @param string|Suggestion $value
+ *
+ * @return $this
+ */
+ public function suggestValue($value): self
+ {
+ $this->valueSuggestions[] = !$value instanceof Suggestion ? new Suggestion($value) : $value;
+
+ return $this;
+ }
+
+ /**
+ * Add multiple suggested values at once for an input option or argument.
+ *
+ * @param list $values
+ *
+ * @return $this
+ */
+ public function suggestValues(array $values): self
+ {
+ foreach ($values as $value) {
+ $this->suggestValue($value);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Add a suggestion for an input option name.
+ *
+ * @return $this
+ */
+ public function suggestOption(InputOption $option): self
+ {
+ $this->optionSuggestions[] = $option;
+
+ return $this;
+ }
+
+ /**
+ * Add multiple suggestions for input option names at once.
+ *
+ * @param InputOption[] $options
+ *
+ * @return $this
+ */
+ public function suggestOptions(array $options): self
+ {
+ foreach ($options as $option) {
+ $this->suggestOption($option);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return InputOption[]
+ */
+ public function getOptionSuggestions(): array
+ {
+ return $this->optionSuggestions;
+ }
+
+ /**
+ * @return Suggestion[]
+ */
+ public function getValueSuggestions(): array
+ {
+ return $this->valueSuggestions;
+ }
+}
diff --git a/vendor/symfony/console/Completion/Output/BashCompletionOutput.php b/vendor/symfony/console/Completion/Output/BashCompletionOutput.php
new file mode 100644
index 000000000..c6f76eb8f
--- /dev/null
+++ b/vendor/symfony/console/Completion/Output/BashCompletionOutput.php
@@ -0,0 +1,33 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Console\Completion\Output;
+
+use Symfony\Component\Console\Completion\CompletionSuggestions;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * @author Wouter de Jong
+ */
+class BashCompletionOutput implements CompletionOutputInterface
+{
+ public function write(CompletionSuggestions $suggestions, OutputInterface $output): void
+ {
+ $values = $suggestions->getValueSuggestions();
+ foreach ($suggestions->getOptionSuggestions() as $option) {
+ $values[] = '--'.$option->getName();
+ if ($option->isNegatable()) {
+ $values[] = '--no-'.$option->getName();
+ }
+ }
+ $output->writeln(implode("\n", $values));
+ }
+}
diff --git a/vendor/symfony/console/Completion/Output/CompletionOutputInterface.php b/vendor/symfony/console/Completion/Output/CompletionOutputInterface.php
new file mode 100644
index 000000000..659e59655
--- /dev/null
+++ b/vendor/symfony/console/Completion/Output/CompletionOutputInterface.php
@@ -0,0 +1,25 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Console\Completion\Output;
+
+use Symfony\Component\Console\Completion\CompletionSuggestions;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * Transforms the {@see CompletionSuggestions} object into output readable by the shell completion.
+ *
+ * @author Wouter de Jong
+ */
+interface CompletionOutputInterface
+{
+ public function write(CompletionSuggestions $suggestions, OutputInterface $output): void;
+}
diff --git a/vendor/symfony/console/Completion/Suggestion.php b/vendor/symfony/console/Completion/Suggestion.php
new file mode 100644
index 000000000..6c7bc4dc4
--- /dev/null
+++ b/vendor/symfony/console/Completion/Suggestion.php
@@ -0,0 +1,37 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Console\Completion;
+
+/**
+ * Represents a single suggested value.
+ *
+ * @author Wouter de Jong
+ */
+class Suggestion
+{
+ private $value;
+
+ public function __construct(string $value)
+ {
+ $this->value = $value;
+ }
+
+ public function getValue(): string
+ {
+ return $this->value;
+ }
+
+ public function __toString(): string
+ {
+ return $this->getValue();
+ }
+}
diff --git a/vendor/symfony/console/ConsoleEvents.php b/vendor/symfony/console/ConsoleEvents.php
index 99b423c83..6ae8f32b8 100644
--- a/vendor/symfony/console/ConsoleEvents.php
+++ b/vendor/symfony/console/ConsoleEvents.php
@@ -11,6 +11,11 @@
namespace Symfony\Component\Console;
+use Symfony\Component\Console\Event\ConsoleCommandEvent;
+use Symfony\Component\Console\Event\ConsoleErrorEvent;
+use Symfony\Component\Console\Event\ConsoleSignalEvent;
+use Symfony\Component\Console\Event\ConsoleTerminateEvent;
+
/**
* Contains all events dispatched by an Application.
*
@@ -27,6 +32,14 @@ final class ConsoleEvents
*/
public const COMMAND = 'console.command';
+ /**
+ * The SIGNAL event allows you to perform some actions
+ * after the command execution was interrupted.
+ *
+ * @Event("Symfony\Component\Console\Event\ConsoleSignalEvent")
+ */
+ public const SIGNAL = 'console.signal';
+
/**
* The TERMINATE event allows you to attach listeners after a command is
* executed by the console.
@@ -44,4 +57,16 @@ final class ConsoleEvents
* @Event("Symfony\Component\Console\Event\ConsoleErrorEvent")
*/
public const ERROR = 'console.error';
+
+ /**
+ * Event aliases.
+ *
+ * These aliases can be consumed by RegisterListenersPass.
+ */
+ public const ALIASES = [
+ ConsoleCommandEvent::class => self::COMMAND,
+ ConsoleErrorEvent::class => self::ERROR,
+ ConsoleSignalEvent::class => self::SIGNAL,
+ ConsoleTerminateEvent::class => self::TERMINATE,
+ ];
}
diff --git a/vendor/symfony/console/Cursor.php b/vendor/symfony/console/Cursor.php
new file mode 100644
index 000000000..0c4dafb6c
--- /dev/null
+++ b/vendor/symfony/console/Cursor.php
@@ -0,0 +1,207 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Console;
+
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * @author Pierre du Plessis
+ */
+final class Cursor
+{
+ private $output;
+ private $input;
+
+ /**
+ * @param resource|null $input
+ */
+ public function __construct(OutputInterface $output, $input = null)
+ {
+ $this->output = $output;
+ $this->input = $input ?? (\defined('STDIN') ? \STDIN : fopen('php://input', 'r+'));
+ }
+
+ /**
+ * @return $this
+ */
+ public function moveUp(int $lines = 1): self
+ {
+ $this->output->write(sprintf("\x1b[%dA", $lines));
+
+ return $this;
+ }
+
+ /**
+ * @return $this
+ */
+ public function moveDown(int $lines = 1): self
+ {
+ $this->output->write(sprintf("\x1b[%dB", $lines));
+
+ return $this;
+ }
+
+ /**
+ * @return $this
+ */
+ public function moveRight(int $columns = 1): self
+ {
+ $this->output->write(sprintf("\x1b[%dC", $columns));
+
+ return $this;
+ }
+
+ /**
+ * @return $this
+ */
+ public function moveLeft(int $columns = 1): self
+ {
+ $this->output->write(sprintf("\x1b[%dD", $columns));
+
+ return $this;
+ }
+
+ /**
+ * @return $this
+ */
+ public function moveToColumn(int $column): self
+ {
+ $this->output->write(sprintf("\x1b[%dG", $column));
+
+ return $this;
+ }
+
+ /**
+ * @return $this
+ */
+ public function moveToPosition(int $column, int $row): self
+ {
+ $this->output->write(sprintf("\x1b[%d;%dH", $row + 1, $column));
+
+ return $this;
+ }
+
+ /**
+ * @return $this
+ */
+ public function savePosition(): self
+ {
+ $this->output->write("\x1b7");
+
+ return $this;
+ }
+
+ /**
+ * @return $this
+ */
+ public function restorePosition(): self
+ {
+ $this->output->write("\x1b8");
+
+ return $this;
+ }
+
+ /**
+ * @return $this
+ */
+ public function hide(): self
+ {
+ $this->output->write("\x1b[?25l");
+
+ return $this;
+ }
+
+ /**
+ * @return $this
+ */
+ public function show(): self
+ {
+ $this->output->write("\x1b[?25h\x1b[?0c");
+
+ return $this;
+ }
+
+ /**
+ * Clears all the output from the current line.
+ *
+ * @return $this
+ */
+ public function clearLine(): self
+ {
+ $this->output->write("\x1b[2K");
+
+ return $this;
+ }
+
+ /**
+ * Clears all the output from the current line after the current position.
+ */
+ public function clearLineAfter(): self
+ {
+ $this->output->write("\x1b[K");
+
+ return $this;
+ }
+
+ /**
+ * Clears all the output from the cursors' current position to the end of the screen.
+ *
+ * @return $this
+ */
+ public function clearOutput(): self
+ {
+ $this->output->write("\x1b[0J");
+
+ return $this;
+ }
+
+ /**
+ * Clears the entire screen.
+ *
+ * @return $this
+ */
+ public function clearScreen(): self
+ {
+ $this->output->write("\x1b[2J");
+
+ return $this;
+ }
+
+ /**
+ * Returns the current cursor position as x,y coordinates.
+ */
+ public function getCurrentPosition(): array
+ {
+ static $isTtySupported;
+
+ if (null === $isTtySupported && \function_exists('proc_open')) {
+ $isTtySupported = (bool) @proc_open('echo 1 >/dev/null', [['file', '/dev/tty', 'r'], ['file', '/dev/tty', 'w'], ['file', '/dev/tty', 'w']], $pipes);
+ }
+
+ if (!$isTtySupported) {
+ return [1, 1];
+ }
+
+ $sttyMode = shell_exec('stty -g');
+ shell_exec('stty -icanon -echo');
+
+ @fwrite($this->input, "\033[6n");
+
+ $code = trim(fread($this->input, 1024));
+
+ shell_exec(sprintf('stty %s', $sttyMode));
+
+ sscanf($code, "\033[%d;%dR", $row, $col);
+
+ return [$col, $row];
+ }
+}
diff --git a/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php b/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php
index 666c8fa59..1fbb212e7 100644
--- a/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php
+++ b/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php
@@ -12,11 +12,14 @@
namespace Symfony\Component\Console\DependencyInjection;
use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Command\LazyCommand;
use Symfony\Component\Console\CommandLoader\ContainerCommandLoader;
+use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
+use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\TypedReference;
/**
@@ -28,11 +31,19 @@ class AddConsoleCommandPass implements CompilerPassInterface
{
private $commandLoaderServiceId;
private $commandTag;
+ private $noPreloadTag;
+ private $privateTagName;
- public function __construct(string $commandLoaderServiceId = 'console.command_loader', string $commandTag = 'console.command')
+ public function __construct(string $commandLoaderServiceId = 'console.command_loader', string $commandTag = 'console.command', string $noPreloadTag = 'container.no_preload', string $privateTagName = 'container.private')
{
+ if (0 < \func_num_args()) {
+ trigger_deprecation('symfony/console', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
+ }
+
$this->commandLoaderServiceId = $commandLoaderServiceId;
$this->commandTag = $commandTag;
+ $this->noPreloadTag = $noPreloadTag;
+ $this->privateTagName = $privateTagName;
}
public function process(ContainerBuilder $container)
@@ -44,10 +55,11 @@ class AddConsoleCommandPass implements CompilerPassInterface
foreach ($commandServices as $id => $tags) {
$definition = $container->getDefinition($id);
+ $definition->addTag($this->noPreloadTag);
$class = $container->getParameterBag()->resolveValue($definition->getClass());
if (isset($tags[0]['command'])) {
- $commandName = $tags[0]['command'];
+ $aliases = $tags[0]['command'];
} else {
if (!$r = $container->getReflectionClass($class)) {
throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
@@ -55,11 +67,18 @@ class AddConsoleCommandPass implements CompilerPassInterface
if (!$r->isSubclassOf(Command::class)) {
throw new InvalidArgumentException(sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, $this->commandTag, Command::class));
}
- $commandName = $class::getDefaultName();
+ $aliases = str_replace('%', '%%', $class::getDefaultName() ?? '');
+ }
+
+ $aliases = explode('|', $aliases ?? '');
+ $commandName = array_shift($aliases);
+
+ if ($isHidden = '' === $commandName) {
+ $commandName = array_shift($aliases);
}
if (null === $commandName) {
- if (!$definition->isPublic() || $definition->isPrivate()) {
+ if (!$definition->isPublic() || $definition->isPrivate() || $definition->hasTag($this->privateTagName)) {
$commandId = 'console.command.public_alias.'.$id;
$container->setAlias($commandId, $id)->setPublic(true);
$id = $commandId;
@@ -69,16 +88,23 @@ class AddConsoleCommandPass implements CompilerPassInterface
continue;
}
+ $description = $tags[0]['description'] ?? null;
+
unset($tags[0]);
$lazyCommandMap[$commandName] = $id;
$lazyCommandRefs[$id] = new TypedReference($id, $class);
- $aliases = [];
+
+ foreach ($aliases as $alias) {
+ $lazyCommandMap[$alias] = $id;
+ }
foreach ($tags as $tag) {
if (isset($tag['command'])) {
$aliases[] = $tag['command'];
$lazyCommandMap[$tag['command']] = $id;
}
+
+ $description = $description ?? $tag['description'] ?? null;
}
$definition->addMethodCall('setName', [$commandName]);
@@ -86,11 +112,35 @@ class AddConsoleCommandPass implements CompilerPassInterface
if ($aliases) {
$definition->addMethodCall('setAliases', [$aliases]);
}
+
+ if ($isHidden) {
+ $definition->addMethodCall('setHidden', [true]);
+ }
+
+ if (!$description) {
+ if (!$r = $container->getReflectionClass($class)) {
+ throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
+ }
+ if (!$r->isSubclassOf(Command::class)) {
+ throw new InvalidArgumentException(sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, $this->commandTag, Command::class));
+ }
+ $description = str_replace('%', '%%', $class::getDefaultDescription() ?? '');
+ }
+
+ if ($description) {
+ $definition->addMethodCall('setDescription', [$description]);
+
+ $container->register('.'.$id.'.lazy', LazyCommand::class)
+ ->setArguments([$commandName, $aliases, $description, $isHidden, new ServiceClosureArgument($lazyCommandRefs[$id])]);
+
+ $lazyCommandRefs[$id] = new Reference('.'.$id.'.lazy');
+ }
}
$container
->register($this->commandLoaderServiceId, ContainerCommandLoader::class)
->setPublic(true)
+ ->addTag($this->noPreloadTag)
->setArguments([ServiceLocatorTagPass::register($container, $lazyCommandRefs), $lazyCommandMap]);
$container->setParameter('console.command.ids', $serviceIds);
diff --git a/vendor/symfony/console/Descriptor/ApplicationDescription.php b/vendor/symfony/console/Descriptor/ApplicationDescription.php
index 3970b9000..2a3acc99b 100644
--- a/vendor/symfony/console/Descriptor/ApplicationDescription.php
+++ b/vendor/symfony/console/Descriptor/ApplicationDescription.php
@@ -34,12 +34,12 @@ class ApplicationDescription
private $namespaces;
/**
- * @var Command[]
+ * @var array
*/
private $commands;
/**
- * @var Command[]
+ * @var array
*/
private $aliases;
@@ -131,7 +131,7 @@ class ApplicationDescription
}
if ($namespacedCommands) {
- ksort($namespacedCommands);
+ ksort($namespacedCommands, \SORT_STRING);
foreach ($namespacedCommands as $key => $commandsSet) {
ksort($commandsSet);
$sortedCommands[$key] = $commandsSet;
diff --git a/vendor/symfony/console/Descriptor/Descriptor.php b/vendor/symfony/console/Descriptor/Descriptor.php
index 9c3878d1e..a3648301f 100644
--- a/vendor/symfony/console/Descriptor/Descriptor.php
+++ b/vendor/symfony/console/Descriptor/Descriptor.php
@@ -34,7 +34,7 @@ abstract class Descriptor implements DescriptorInterface
/**
* {@inheritdoc}
*/
- public function describe(OutputInterface $output, $object, array $options = [])
+ public function describe(OutputInterface $output, object $object, array $options = [])
{
$this->output = $output;
@@ -55,17 +55,14 @@ abstract class Descriptor implements DescriptorInterface
$this->describeApplication($object, $options);
break;
default:
- throw new InvalidArgumentException(sprintf('Object of type "%s" is not describable.', \get_class($object)));
+ throw new InvalidArgumentException(sprintf('Object of type "%s" is not describable.', get_debug_type($object)));
}
}
/**
* Writes content to output.
- *
- * @param string $content
- * @param bool $decorated
*/
- protected function write($content, $decorated = false)
+ protected function write(string $content, bool $decorated = false)
{
$this->output->write($content, false, $decorated ? OutputInterface::OUTPUT_NORMAL : OutputInterface::OUTPUT_RAW);
}
diff --git a/vendor/symfony/console/Descriptor/DescriptorInterface.php b/vendor/symfony/console/Descriptor/DescriptorInterface.php
index e3184a6a5..ebea30367 100644
--- a/vendor/symfony/console/Descriptor/DescriptorInterface.php
+++ b/vendor/symfony/console/Descriptor/DescriptorInterface.php
@@ -20,10 +20,5 @@ use Symfony\Component\Console\Output\OutputInterface;
*/
interface DescriptorInterface
{
- /**
- * Describes an object if supported.
- *
- * @param object $object
- */
- public function describe(OutputInterface $output, $object, array $options = []);
+ public function describe(OutputInterface $output, object $object, array $options = []);
}
diff --git a/vendor/symfony/console/Descriptor/JsonDescriptor.php b/vendor/symfony/console/Descriptor/JsonDescriptor.php
index 4c09e1267..1d2865941 100644
--- a/vendor/symfony/console/Descriptor/JsonDescriptor.php
+++ b/vendor/symfony/console/Descriptor/JsonDescriptor.php
@@ -40,6 +40,9 @@ class JsonDescriptor extends Descriptor
protected function describeInputOption(InputOption $option, array $options = [])
{
$this->writeData($this->getInputOptionData($option), $options);
+ if ($option->isNegatable()) {
+ $this->writeData($this->getInputOptionData($option, true), $options);
+ }
}
/**
@@ -55,7 +58,7 @@ class JsonDescriptor extends Descriptor
*/
protected function describeCommand(Command $command, array $options = [])
{
- $this->writeData($this->getCommandData($command), $options);
+ $this->writeData($this->getCommandData($command, $options['short'] ?? false), $options);
}
/**
@@ -68,7 +71,7 @@ class JsonDescriptor extends Descriptor
$commands = [];
foreach ($description->getCommands() as $command) {
- $commands[] = $this->getCommandData($command);
+ $commands[] = $this->getCommandData($command, $options['short'] ?? false);
}
$data = [];
@@ -111,9 +114,17 @@ class JsonDescriptor extends Descriptor
];
}
- private function getInputOptionData(InputOption $option): array
+ private function getInputOptionData(InputOption $option, bool $negated = false): array
{
- return [
+ return $negated ? [
+ 'name' => '--no-'.$option->getName(),
+ 'shortcut' => '',
+ 'accept_value' => false,
+ 'is_value_required' => false,
+ 'is_multiple' => false,
+ 'description' => 'Negate the "--'.$option->getName().'" option',
+ 'default' => false,
+ ] : [
'name' => '--'.$option->getName(),
'shortcut' => $option->getShortcut() ? '-'.str_replace('|', '|-', $option->getShortcut()) : '',
'accept_value' => $option->acceptValue(),
@@ -134,23 +145,37 @@ class JsonDescriptor extends Descriptor
$inputOptions = [];
foreach ($definition->getOptions() as $name => $option) {
$inputOptions[$name] = $this->getInputOptionData($option);
+ if ($option->isNegatable()) {
+ $inputOptions['no-'.$name] = $this->getInputOptionData($option, true);
+ }
}
return ['arguments' => $inputArguments, 'options' => $inputOptions];
}
- private function getCommandData(Command $command): array
+ private function getCommandData(Command $command, bool $short = false): array
{
- $command->getSynopsis();
- $command->mergeApplicationDefinition(false);
-
- return [
+ $data = [
'name' => $command->getName(),
- 'usage' => array_merge([$command->getSynopsis()], $command->getUsages(), $command->getAliases()),
'description' => $command->getDescription(),
- 'help' => $command->getProcessedHelp(),
- 'definition' => $this->getInputDefinitionData($command->getNativeDefinition()),
- 'hidden' => $command->isHidden(),
];
+
+ if ($short) {
+ $data += [
+ 'usage' => $command->getAliases(),
+ ];
+ } else {
+ $command->mergeApplicationDefinition(false);
+
+ $data += [
+ 'usage' => array_merge([$command->getSynopsis()], $command->getUsages(), $command->getAliases()),
+ 'help' => $command->getProcessedHelp(),
+ 'definition' => $this->getInputDefinitionData($command->getDefinition()),
+ ];
+ }
+
+ $data['hidden'] = $command->isHidden();
+
+ return $data;
}
}
diff --git a/vendor/symfony/console/Descriptor/MarkdownDescriptor.php b/vendor/symfony/console/Descriptor/MarkdownDescriptor.php
index 9a9d28075..21ceca6c2 100644
--- a/vendor/symfony/console/Descriptor/MarkdownDescriptor.php
+++ b/vendor/symfony/console/Descriptor/MarkdownDescriptor.php
@@ -31,7 +31,7 @@ class MarkdownDescriptor extends Descriptor
/**
* {@inheritdoc}
*/
- public function describe(OutputInterface $output, $object, array $options = [])
+ public function describe(OutputInterface $output, object $object, array $options = [])
{
$decorated = $output->isDecorated();
$output->setDecorated(false);
@@ -44,7 +44,7 @@ class MarkdownDescriptor extends Descriptor
/**
* {@inheritdoc}
*/
- protected function write($content, $decorated = true)
+ protected function write(string $content, bool $decorated = true)
{
parent::write($content, $decorated);
}
@@ -69,6 +69,9 @@ class MarkdownDescriptor extends Descriptor
protected function describeInputOption(InputOption $option, array $options = [])
{
$name = '--'.$option->getName();
+ if ($option->isNegatable()) {
+ $name .= '|--no-'.$option->getName();
+ }
if ($option->getShortcut()) {
$name .= '|-'.str_replace('|', '|-', $option->getShortcut()).'';
}
@@ -79,6 +82,7 @@ class MarkdownDescriptor extends Descriptor
.'* Accept value: '.($option->acceptValue() ? 'yes' : 'no')."\n"
.'* Is value required: '.($option->isValueRequired() ? 'yes' : 'no')."\n"
.'* Is multiple: '.($option->isArray() ? 'yes' : 'no')."\n"
+ .'* Is negatable: '.($option->isNegatable() ? 'yes' : 'no')."\n"
.'* Default: `'.str_replace("\n", '', var_export($option->getDefault(), true)).'`'
);
}
@@ -92,7 +96,9 @@ class MarkdownDescriptor extends Descriptor
$this->write('### Arguments');
foreach ($definition->getArguments() as $argument) {
$this->write("\n\n");
- $this->write($this->describeInputArgument($argument));
+ if (null !== $describeInputArgument = $this->describeInputArgument($argument)) {
+ $this->write($describeInputArgument);
+ }
}
}
@@ -104,7 +110,9 @@ class MarkdownDescriptor extends Descriptor
$this->write('### Options');
foreach ($definition->getOptions() as $option) {
$this->write("\n\n");
- $this->write($this->describeInputOption($option));
+ if (null !== $describeInputOption = $this->describeInputOption($option)) {
+ $this->write($describeInputOption);
+ }
}
}
}
@@ -114,12 +122,25 @@ class MarkdownDescriptor extends Descriptor
*/
protected function describeCommand(Command $command, array $options = [])
{
- $command->getSynopsis();
+ if ($options['short'] ?? false) {
+ $this->write(
+ '`'.$command->getName()."`\n"
+ .str_repeat('-', Helper::width($command->getName()) + 2)."\n\n"
+ .($command->getDescription() ? $command->getDescription()."\n\n" : '')
+ .'### Usage'."\n\n"
+ .array_reduce($command->getAliases(), function ($carry, $usage) {
+ return $carry.'* `'.$usage.'`'."\n";
+ })
+ );
+
+ return;
+ }
+
$command->mergeApplicationDefinition(false);
$this->write(
'`'.$command->getName()."`\n"
- .str_repeat('-', Helper::strlen($command->getName()) + 2)."\n\n"
+ .str_repeat('-', Helper::width($command->getName()) + 2)."\n\n"
.($command->getDescription() ? $command->getDescription()."\n\n" : '')
.'### Usage'."\n\n"
.array_reduce(array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()), function ($carry, $usage) {
@@ -132,9 +153,10 @@ class MarkdownDescriptor extends Descriptor
$this->write($help);
}
- if ($command->getNativeDefinition()) {
+ $definition = $command->getDefinition();
+ if ($definition->getOptions() || $definition->getArguments()) {
$this->write("\n\n");
- $this->describeInputDefinition($command->getNativeDefinition());
+ $this->describeInputDefinition($definition);
}
}
@@ -147,7 +169,7 @@ class MarkdownDescriptor extends Descriptor
$description = new ApplicationDescription($application, $describedNamespace);
$title = $this->getApplicationTitle($application);
- $this->write($title."\n".str_repeat('=', Helper::strlen($title)));
+ $this->write($title."\n".str_repeat('=', Helper::width($title)));
foreach ($description->getNamespaces() as $namespace) {
if (ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) {
@@ -163,7 +185,9 @@ class MarkdownDescriptor extends Descriptor
foreach ($description->getCommands() as $command) {
$this->write("\n\n");
- $this->write($this->describeCommand($command));
+ if (null !== $describeCommand = $this->describeCommand($command, $options)) {
+ $this->write($describeCommand);
+ }
}
}
diff --git a/vendor/symfony/console/Descriptor/TextDescriptor.php b/vendor/symfony/console/Descriptor/TextDescriptor.php
index 7d4d5f0bb..fbb140ae7 100644
--- a/vendor/symfony/console/Descriptor/TextDescriptor.php
+++ b/vendor/symfony/console/Descriptor/TextDescriptor.php
@@ -39,7 +39,7 @@ class TextDescriptor extends Descriptor
$default = '';
}
- $totalWidth = $options['total_width'] ?? Helper::strlen($argument->getName());
+ $totalWidth = $options['total_width'] ?? Helper::width($argument->getName());
$spacingWidth = $totalWidth - \strlen($argument->getName());
$this->writeText(sprintf(' %s %s%s%s',
@@ -74,10 +74,10 @@ class TextDescriptor extends Descriptor
$totalWidth = $options['total_width'] ?? $this->calculateTotalWidthForOptions([$option]);
$synopsis = sprintf('%s%s',
$option->getShortcut() ? sprintf('-%s, ', $option->getShortcut()) : ' ',
- sprintf('--%s%s', $option->getName(), $value)
+ sprintf($option->isNegatable() ? '--%1$s|--no-%1$s' : '--%1$s%2$s', $option->getName(), $value)
);
- $spacingWidth = $totalWidth - Helper::strlen($synopsis);
+ $spacingWidth = $totalWidth - Helper::width($synopsis);
$this->writeText(sprintf(' %s %s%s%s%s',
$synopsis,
@@ -96,7 +96,7 @@ class TextDescriptor extends Descriptor
{
$totalWidth = $this->calculateTotalWidthForOptions($definition->getOptions());
foreach ($definition->getArguments() as $argument) {
- $totalWidth = max($totalWidth, Helper::strlen($argument->getName()));
+ $totalWidth = max($totalWidth, Helper::width($argument->getName()));
}
if ($definition->getArguments()) {
@@ -136,8 +136,6 @@ class TextDescriptor extends Descriptor
*/
protected function describeCommand(Command $command, array $options = [])
{
- $command->getSynopsis(true);
- $command->getSynopsis(false);
$command->mergeApplicationDefinition(false);
if ($description = $command->getDescription()) {
@@ -154,7 +152,7 @@ class TextDescriptor extends Descriptor
}
$this->writeText("\n");
- $definition = $command->getNativeDefinition();
+ $definition = $command->getDefinition();
if ($definition->getOptions() || $definition->getArguments()) {
$this->writeText("\n");
$this->describeInputDefinition($definition, $options);
@@ -236,7 +234,7 @@ class TextDescriptor extends Descriptor
foreach ($namespace['commands'] as $name) {
$this->writeText("\n");
- $spacingWidth = $width - Helper::strlen($name);
+ $spacingWidth = $width - Helper::width($name);
$command = $commands[$name];
$commandAliases = $name === $command->getName() ? $this->getCommandAliasesText($command) : '';
$this->writeText(sprintf(' %s%s%s', $name, str_repeat(' ', $spacingWidth), $commandAliases.$command->getDescription()), $options);
@@ -306,12 +304,12 @@ class TextDescriptor extends Descriptor
foreach ($commands as $command) {
if ($command instanceof Command) {
- $widths[] = Helper::strlen($command->getName());
+ $widths[] = Helper::width($command->getName());
foreach ($command->getAliases() as $alias) {
- $widths[] = Helper::strlen($alias);
+ $widths[] = Helper::width($alias);
}
} else {
- $widths[] = Helper::strlen($command);
+ $widths[] = Helper::width($command);
}
}
@@ -326,10 +324,11 @@ class TextDescriptor extends Descriptor
$totalWidth = 0;
foreach ($options as $option) {
// "-" + shortcut + ", --" + name
- $nameLength = 1 + max(Helper::strlen($option->getShortcut()), 1) + 4 + Helper::strlen($option->getName());
-
- if ($option->acceptValue()) {
- $valueLength = 1 + Helper::strlen($option->getName()); // = + value
+ $nameLength = 1 + max(Helper::width($option->getShortcut()), 1) + 4 + Helper::width($option->getName());
+ if ($option->isNegatable()) {
+ $nameLength += 6 + Helper::width($option->getName()); // |--no- + name
+ } elseif ($option->acceptValue()) {
+ $valueLength = 1 + Helper::width($option->getName()); // = + value
$valueLength += $option->isValueOptional() ? 2 : 0; // [ + ]
$nameLength += $valueLength;
diff --git a/vendor/symfony/console/Descriptor/XmlDescriptor.php b/vendor/symfony/console/Descriptor/XmlDescriptor.php
index e0ed53a38..4f7cd8b3e 100644
--- a/vendor/symfony/console/Descriptor/XmlDescriptor.php
+++ b/vendor/symfony/console/Descriptor/XmlDescriptor.php
@@ -44,37 +44,42 @@ class XmlDescriptor extends Descriptor
return $dom;
}
- public function getCommandDocument(Command $command): \DOMDocument
+ public function getCommandDocument(Command $command, bool $short = false): \DOMDocument
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($commandXML = $dom->createElement('command'));
- $command->getSynopsis();
- $command->mergeApplicationDefinition(false);
-
$commandXML->setAttribute('id', $command->getName());
$commandXML->setAttribute('name', $command->getName());
$commandXML->setAttribute('hidden', $command->isHidden() ? 1 : 0);
$commandXML->appendChild($usagesXML = $dom->createElement('usages'));
- foreach (array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()) as $usage) {
- $usagesXML->appendChild($dom->createElement('usage', $usage));
- }
-
$commandXML->appendChild($descriptionXML = $dom->createElement('description'));
$descriptionXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getDescription())));
- $commandXML->appendChild($helpXML = $dom->createElement('help'));
- $helpXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getProcessedHelp())));
+ if ($short) {
+ foreach ($command->getAliases() as $usage) {
+ $usagesXML->appendChild($dom->createElement('usage', $usage));
+ }
+ } else {
+ $command->mergeApplicationDefinition(false);
- $definitionXML = $this->getInputDefinitionDocument($command->getNativeDefinition());
- $this->appendDocument($commandXML, $definitionXML->getElementsByTagName('definition')->item(0));
+ foreach (array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()) as $usage) {
+ $usagesXML->appendChild($dom->createElement('usage', $usage));
+ }
+
+ $commandXML->appendChild($helpXML = $dom->createElement('help'));
+ $helpXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getProcessedHelp())));
+
+ $definitionXML = $this->getInputDefinitionDocument($command->getDefinition());
+ $this->appendDocument($commandXML, $definitionXML->getElementsByTagName('definition')->item(0));
+ }
return $dom;
}
- public function getApplicationDocument(Application $application, string $namespace = null): \DOMDocument
+ public function getApplicationDocument(Application $application, string $namespace = null, bool $short = false): \DOMDocument
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($rootXml = $dom->createElement('symfony'));
@@ -95,7 +100,7 @@ class XmlDescriptor extends Descriptor
}
foreach ($description->getCommands() as $command) {
- $this->appendDocument($commandsXML, $this->getCommandDocument($command));
+ $this->appendDocument($commandsXML, $this->getCommandDocument($command, $short));
}
if (!$namespace) {
@@ -144,7 +149,7 @@ class XmlDescriptor extends Descriptor
*/
protected function describeCommand(Command $command, array $options = [])
{
- $this->writeDocument($this->getCommandDocument($command));
+ $this->writeDocument($this->getCommandDocument($command, $options['short'] ?? false));
}
/**
@@ -152,7 +157,7 @@ class XmlDescriptor extends Descriptor
*/
protected function describeApplication(Application $application, array $options = [])
{
- $this->writeDocument($this->getApplicationDocument($application, $options['namespace'] ?? null));
+ $this->writeDocument($this->getApplicationDocument($application, $options['namespace'] ?? null, $options['short'] ?? false));
}
/**
@@ -226,6 +231,17 @@ class XmlDescriptor extends Descriptor
}
}
+ if ($option->isNegatable()) {
+ $dom->appendChild($objectXML = $dom->createElement('option'));
+ $objectXML->setAttribute('name', '--no-'.$option->getName());
+ $objectXML->setAttribute('shortcut', '');
+ $objectXML->setAttribute('accept_value', 0);
+ $objectXML->setAttribute('is_value_required', 0);
+ $objectXML->setAttribute('is_multiple', 0);
+ $objectXML->appendChild($descriptionXML = $dom->createElement('description'));
+ $descriptionXML->appendChild($dom->createTextNode('Negate the "--'.$option->getName().'" option'));
+ }
+
return $dom;
}
}
diff --git a/vendor/symfony/console/Event/ConsoleCommandEvent.php b/vendor/symfony/console/Event/ConsoleCommandEvent.php
index 9691db636..08bd18fd1 100644
--- a/vendor/symfony/console/Event/ConsoleCommandEvent.php
+++ b/vendor/symfony/console/Event/ConsoleCommandEvent.php
@@ -15,10 +15,8 @@ namespace Symfony\Component\Console\Event;
* Allows to do things before the command is executed, like skipping the command or changing the input.
*
* @author Fabien Potencier
- *
- * @final since Symfony 4.4
*/
-class ConsoleCommandEvent extends ConsoleEvent
+final class ConsoleCommandEvent extends ConsoleEvent
{
/**
* The return code for skipped commands, this will also be passed into the terminate event.
@@ -32,30 +30,21 @@ class ConsoleCommandEvent extends ConsoleEvent
/**
* Disables the command, so it won't be run.
- *
- * @return bool
*/
- public function disableCommand()
+ public function disableCommand(): bool
{
return $this->commandShouldRun = false;
}
- /**
- * Enables the command.
- *
- * @return bool
- */
- public function enableCommand()
+ public function enableCommand(): bool
{
return $this->commandShouldRun = true;
}
/**
* Returns true if the command is runnable, false otherwise.
- *
- * @return bool
*/
- public function commandShouldRun()
+ public function commandShouldRun(): bool
{
return $this->commandShouldRun;
}
diff --git a/vendor/symfony/console/Event/ConsoleEvent.php b/vendor/symfony/console/Event/ConsoleEvent.php
index 400eb5731..be7937d51 100644
--- a/vendor/symfony/console/Event/ConsoleEvent.php
+++ b/vendor/symfony/console/Event/ConsoleEvent.php
@@ -14,7 +14,7 @@ namespace Symfony\Component\Console\Event;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
-use Symfony\Component\EventDispatcher\Event;
+use Symfony\Contracts\EventDispatcher\Event;
/**
* Allows to inspect input and output of a command.
@@ -38,7 +38,7 @@ class ConsoleEvent extends Event
/**
* Gets the command that is executed.
*
- * @return Command|null A Command instance
+ * @return Command|null
*/
public function getCommand()
{
@@ -48,7 +48,7 @@ class ConsoleEvent extends Event
/**
* Gets the input instance.
*
- * @return InputInterface An InputInterface instance
+ * @return InputInterface
*/
public function getInput()
{
@@ -58,7 +58,7 @@ class ConsoleEvent extends Event
/**
* Gets the output instance.
*
- * @return OutputInterface An OutputInterface instance
+ * @return OutputInterface
*/
public function getOutput()
{
diff --git a/vendor/symfony/console/Event/ConsoleSignalEvent.php b/vendor/symfony/console/Event/ConsoleSignalEvent.php
new file mode 100644
index 000000000..ef13ed2f5
--- /dev/null
+++ b/vendor/symfony/console/Event/ConsoleSignalEvent.php
@@ -0,0 +1,35 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Console\Event;
+
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * @author marie
+ */
+final class ConsoleSignalEvent extends ConsoleEvent
+{
+ private $handlingSignal;
+
+ public function __construct(Command $command, InputInterface $input, OutputInterface $output, int $handlingSignal)
+ {
+ parent::__construct($command, $input, $output);
+ $this->handlingSignal = $handlingSignal;
+ }
+
+ public function getHandlingSignal(): int
+ {
+ return $this->handlingSignal;
+ }
+}
diff --git a/vendor/symfony/console/Event/ConsoleTerminateEvent.php b/vendor/symfony/console/Event/ConsoleTerminateEvent.php
index 43d0f8ab1..190038d1a 100644
--- a/vendor/symfony/console/Event/ConsoleTerminateEvent.php
+++ b/vendor/symfony/console/Event/ConsoleTerminateEvent.php
@@ -19,10 +19,8 @@ use Symfony\Component\Console\Output\OutputInterface;
* Allows to manipulate the exit code of a command after its execution.
*
* @author Francesco Levorato
- *
- * @final since Symfony 4.4
*/
-class ConsoleTerminateEvent extends ConsoleEvent
+final class ConsoleTerminateEvent extends ConsoleEvent
{
private $exitCode;
@@ -33,22 +31,12 @@ class ConsoleTerminateEvent extends ConsoleEvent
$this->setExitCode($exitCode);
}
- /**
- * Sets the exit code.
- *
- * @param int $exitCode The command exit code
- */
- public function setExitCode($exitCode)
+ public function setExitCode(int $exitCode): void
{
- $this->exitCode = (int) $exitCode;
+ $this->exitCode = $exitCode;
}
- /**
- * Gets the exit code.
- *
- * @return int The command exit code
- */
- public function getExitCode()
+ public function getExitCode(): int
{
return $this->exitCode;
}
diff --git a/vendor/symfony/console/Exception/CommandNotFoundException.php b/vendor/symfony/console/Exception/CommandNotFoundException.php
index 590a71c77..910ae1928 100644
--- a/vendor/symfony/console/Exception/CommandNotFoundException.php
+++ b/vendor/symfony/console/Exception/CommandNotFoundException.php
@@ -34,7 +34,7 @@ class CommandNotFoundException extends \InvalidArgumentException implements Exce
}
/**
- * @return string[] A list of similar defined names
+ * @return string[]
*/
public function getAlternatives()
{
diff --git a/vendor/symfony/console/Exception/InvalidOptionException.php b/vendor/symfony/console/Exception/InvalidOptionException.php
index b2eec6165..5cf62792e 100644
--- a/vendor/symfony/console/Exception/InvalidOptionException.php
+++ b/vendor/symfony/console/Exception/InvalidOptionException.php
@@ -12,7 +12,7 @@
namespace Symfony\Component\Console\Exception;
/**
- * Represents an incorrect option name typed in the console.
+ * Represents an incorrect option name or value typed in the console.
*
* @author Jérôme Tamarelle
*/
diff --git a/vendor/symfony/console/Formatter/NullOutputFormatter.php b/vendor/symfony/console/Formatter/NullOutputFormatter.php
new file mode 100644
index 000000000..d770e1465
--- /dev/null
+++ b/vendor/symfony/console/Formatter/NullOutputFormatter.php
@@ -0,0 +1,69 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Console\Formatter;
+
+/**
+ * @author Tien Xuan Vo
+ */
+final class NullOutputFormatter implements OutputFormatterInterface
+{
+ private $style;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function format(?string $message): ?string
+ {
+ return null;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getStyle(string $name): OutputFormatterStyleInterface
+ {
+ // to comply with the interface we must return a OutputFormatterStyleInterface
+ return $this->style ?? $this->style = new NullOutputFormatterStyle();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function hasStyle(string $name): bool
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isDecorated(): bool
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setDecorated(bool $decorated): void
+ {
+ // do nothing
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setStyle(string $name, OutputFormatterStyleInterface $style): void
+ {
+ // do nothing
+ }
+}
diff --git a/vendor/symfony/console/Formatter/NullOutputFormatterStyle.php b/vendor/symfony/console/Formatter/NullOutputFormatterStyle.php
new file mode 100644
index 000000000..9232510f4
--- /dev/null
+++ b/vendor/symfony/console/Formatter/NullOutputFormatterStyle.php
@@ -0,0 +1,66 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Console\Formatter;
+
+/**
+ * @author Tien Xuan Vo
+ */
+final class NullOutputFormatterStyle implements OutputFormatterStyleInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function apply(string $text): string
+ {
+ return $text;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setBackground(string $color = null): void
+ {
+ // do nothing
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setForeground(string $color = null): void
+ {
+ // do nothing
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setOption(string $option): void
+ {
+ // do nothing
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setOptions(array $options): void
+ {
+ // do nothing
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function unsetOption(string $option): void
+ {
+ // do nothing
+ }
+}
diff --git a/vendor/symfony/console/Formatter/OutputFormatter.php b/vendor/symfony/console/Formatter/OutputFormatter.php
index e8c10e700..603e5dca0 100644
--- a/vendor/symfony/console/Formatter/OutputFormatter.php
+++ b/vendor/symfony/console/Formatter/OutputFormatter.php
@@ -36,11 +36,9 @@ class OutputFormatter implements WrappableOutputFormatterInterface
/**
* Escapes "<" and ">" special chars in given text.
*
- * @param string $text Text to escape
- *
- * @return string Escaped text
+ * @return string
*/
- public static function escape($text)
+ public static function escape(string $text)
{
$text = preg_replace('/([^\\\\]|^)([<>])/', '$1\\\\$2', $text);
@@ -88,9 +86,9 @@ class OutputFormatter implements WrappableOutputFormatterInterface
/**
* {@inheritdoc}
*/
- public function setDecorated($decorated)
+ public function setDecorated(bool $decorated)
{
- $this->decorated = (bool) $decorated;
+ $this->decorated = $decorated;
}
/**
@@ -104,7 +102,7 @@ class OutputFormatter implements WrappableOutputFormatterInterface
/**
* {@inheritdoc}
*/
- public function setStyle($name, OutputFormatterStyleInterface $style)
+ public function setStyle(string $name, OutputFormatterStyleInterface $style)
{
$this->styles[strtolower($name)] = $style;
}
@@ -112,7 +110,7 @@ class OutputFormatter implements WrappableOutputFormatterInterface
/**
* {@inheritdoc}
*/
- public function hasStyle($name)
+ public function hasStyle(string $name)
{
return isset($this->styles[strtolower($name)]);
}
@@ -120,7 +118,7 @@ class OutputFormatter implements WrappableOutputFormatterInterface
/**
* {@inheritdoc}
*/
- public function getStyle($name)
+ public function getStyle(string $name)
{
if (!$this->hasStyle($name)) {
throw new InvalidArgumentException(sprintf('Undefined style: "%s".', $name));
@@ -132,16 +130,20 @@ class OutputFormatter implements WrappableOutputFormatterInterface
/**
* {@inheritdoc}
*/
- public function format($message)
+ public function format(?string $message)
{
- return $this->formatAndWrap((string) $message, 0);
+ return $this->formatAndWrap($message, 0);
}
/**
* {@inheritdoc}
*/
- public function formatAndWrap(string $message, int $width)
+ public function formatAndWrap(?string $message, int $width)
{
+ if (null === $message) {
+ return '';
+ }
+
$offset = 0;
$output = '';
$openTagRegex = '[a-z](?:[^\\\\<>]*+ | \\\\.)*';
diff --git a/vendor/symfony/console/Formatter/OutputFormatterInterface.php b/vendor/symfony/console/Formatter/OutputFormatterInterface.php
index 22f40a34e..0b5f839a2 100644
--- a/vendor/symfony/console/Formatter/OutputFormatterInterface.php
+++ b/vendor/symfony/console/Formatter/OutputFormatterInterface.php
@@ -20,51 +20,41 @@ interface OutputFormatterInterface
{
/**
* Sets the decorated flag.
- *
- * @param bool $decorated Whether to decorate the messages or not
*/
- public function setDecorated($decorated);
+ public function setDecorated(bool $decorated);
/**
- * Gets the decorated flag.
+ * Whether the output will decorate messages.
*
- * @return bool true if the output will decorate messages, false otherwise
+ * @return bool
*/
public function isDecorated();
/**
* Sets a new style.
- *
- * @param string $name The style name
*/
- public function setStyle($name, OutputFormatterStyleInterface $style);
+ public function setStyle(string $name, OutputFormatterStyleInterface $style);
/**
* Checks if output formatter has style with specified name.
*
- * @param string $name
- *
* @return bool
*/
- public function hasStyle($name);
+ public function hasStyle(string $name);
/**
* Gets style options from style with specified name.
*
- * @param string $name
- *
* @return OutputFormatterStyleInterface
*
* @throws \InvalidArgumentException When style isn't defined
*/
- public function getStyle($name);
+ public function getStyle(string $name);
/**
* Formats a message according to the given styles.
*
- * @param string $message The message to style
- *
- * @return string The styled message
+ * @return string|null
*/
- public function format($message);
+ public function format(?string $message);
}
diff --git a/vendor/symfony/console/Formatter/OutputFormatterStyle.php b/vendor/symfony/console/Formatter/OutputFormatterStyle.php
index 7cb6116b4..8370ba058 100644
--- a/vendor/symfony/console/Formatter/OutputFormatterStyle.php
+++ b/vendor/symfony/console/Formatter/OutputFormatterStyle.php
@@ -11,7 +11,7 @@
namespace Symfony\Component\Console\Formatter;
-use Symfony\Component\Console\Exception\InvalidArgumentException;
+use Symfony\Component\Console\Color;
/**
* Formatter style class for defining styles.
@@ -20,40 +20,11 @@ use Symfony\Component\Console\Exception\InvalidArgumentException;
*/
class OutputFormatterStyle implements OutputFormatterStyleInterface
{
- private static $availableForegroundColors = [
- 'black' => ['set' => 30, 'unset' => 39],
- 'red' => ['set' => 31, 'unset' => 39],
- 'green' => ['set' => 32, 'unset' => 39],
- 'yellow' => ['set' => 33, 'unset' => 39],
- 'blue' => ['set' => 34, 'unset' => 39],
- 'magenta' => ['set' => 35, 'unset' => 39],
- 'cyan' => ['set' => 36, 'unset' => 39],
- 'white' => ['set' => 37, 'unset' => 39],
- 'default' => ['set' => 39, 'unset' => 39],
- ];
- private static $availableBackgroundColors = [
- 'black' => ['set' => 40, 'unset' => 49],
- 'red' => ['set' => 41, 'unset' => 49],
- 'green' => ['set' => 42, 'unset' => 49],
- 'yellow' => ['set' => 43, 'unset' => 49],
- 'blue' => ['set' => 44, 'unset' => 49],
- 'magenta' => ['set' => 45, 'unset' => 49],
- 'cyan' => ['set' => 46, 'unset' => 49],
- 'white' => ['set' => 47, 'unset' => 49],
- 'default' => ['set' => 49, 'unset' => 49],
- ];
- private static $availableOptions = [
- 'bold' => ['set' => 1, 'unset' => 22],
- 'underscore' => ['set' => 4, 'unset' => 24],
- 'blink' => ['set' => 5, 'unset' => 25],
- 'reverse' => ['set' => 7, 'unset' => 27],
- 'conceal' => ['set' => 8, 'unset' => 28],
- ];
-
+ private $color;
private $foreground;
private $background;
+ private $options;
private $href;
- private $options = [];
private $handlesHrefGracefully;
/**
@@ -64,51 +35,23 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface
*/
public function __construct(string $foreground = null, string $background = null, array $options = [])
{
- if (null !== $foreground) {
- $this->setForeground($foreground);
- }
- if (null !== $background) {
- $this->setBackground($background);
- }
- if (\count($options)) {
- $this->setOptions($options);
- }
+ $this->color = new Color($this->foreground = $foreground ?: '', $this->background = $background ?: '', $this->options = $options);
}
/**
* {@inheritdoc}
*/
- public function setForeground($color = null)
+ public function setForeground(string $color = null)
{
- if (null === $color) {
- $this->foreground = null;
-
- return;
- }
-
- if (!isset(static::$availableForegroundColors[$color])) {
- throw new InvalidArgumentException(sprintf('Invalid foreground color specified: "%s". Expected one of (%s).', $color, implode(', ', array_keys(static::$availableForegroundColors))));
- }
-
- $this->foreground = static::$availableForegroundColors[$color];
+ $this->color = new Color($this->foreground = $color ?: '', $this->background, $this->options);
}
/**
* {@inheritdoc}
*/
- public function setBackground($color = null)
+ public function setBackground(string $color = null)
{
- if (null === $color) {
- $this->background = null;
-
- return;
- }
-
- if (!isset(static::$availableBackgroundColors[$color])) {
- throw new InvalidArgumentException(sprintf('Invalid background color specified: "%s". Expected one of (%s).', $color, implode(', ', array_keys(static::$availableBackgroundColors))));
- }
-
- $this->background = static::$availableBackgroundColors[$color];
+ $this->color = new Color($this->foreground, $this->background = $color ?: '', $this->options);
}
public function setHref(string $url): void
@@ -119,30 +62,23 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface
/**
* {@inheritdoc}
*/
- public function setOption($option)
+ public function setOption(string $option)
{
- if (!isset(static::$availableOptions[$option])) {
- throw new InvalidArgumentException(sprintf('Invalid option specified: "%s". Expected one of (%s).', $option, implode(', ', array_keys(static::$availableOptions))));
- }
-
- if (!\in_array(static::$availableOptions[$option], $this->options)) {
- $this->options[] = static::$availableOptions[$option];
- }
+ $this->options[] = $option;
+ $this->color = new Color($this->foreground, $this->background, $this->options);
}
/**
* {@inheritdoc}
*/
- public function unsetOption($option)
+ public function unsetOption(string $option)
{
- if (!isset(static::$availableOptions[$option])) {
- throw new InvalidArgumentException(sprintf('Invalid option specified: "%s". Expected one of (%s).', $option, implode(', ', array_keys(static::$availableOptions))));
- }
-
- $pos = array_search(static::$availableOptions[$option], $this->options);
+ $pos = array_search($option, $this->options);
if (false !== $pos) {
unset($this->options[$pos]);
}
+
+ $this->color = new Color($this->foreground, $this->background, $this->options);
}
/**
@@ -150,48 +86,24 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface
*/
public function setOptions(array $options)
{
- $this->options = [];
-
- foreach ($options as $option) {
- $this->setOption($option);
- }
+ $this->color = new Color($this->foreground, $this->background, $this->options = $options);
}
/**
* {@inheritdoc}
*/
- public function apply($text)
+ public function apply(string $text)
{
- $setCodes = [];
- $unsetCodes = [];
-
if (null === $this->handlesHrefGracefully) {
$this->handlesHrefGracefully = 'JetBrains-JediTerm' !== getenv('TERMINAL_EMULATOR')
- && (!getenv('KONSOLE_VERSION') || (int) getenv('KONSOLE_VERSION') > 201100);
- }
-
- if (null !== $this->foreground) {
- $setCodes[] = $this->foreground['set'];
- $unsetCodes[] = $this->foreground['unset'];
- }
- if (null !== $this->background) {
- $setCodes[] = $this->background['set'];
- $unsetCodes[] = $this->background['unset'];
- }
-
- foreach ($this->options as $option) {
- $setCodes[] = $option['set'];
- $unsetCodes[] = $option['unset'];
+ && (!getenv('KONSOLE_VERSION') || (int) getenv('KONSOLE_VERSION') > 201100)
+ && !isset($_SERVER['IDEA_INITIAL_DIRECTORY']);
}
if (null !== $this->href && $this->handlesHrefGracefully) {
$text = "\033]8;;$this->href\033\\$text\033]8;;\033\\";
}
- if (0 === \count($setCodes)) {
- return $text;
- }
-
- return sprintf("\033[%sm%s\033[%sm", implode(';', $setCodes), $text, implode(';', $unsetCodes));
+ return $this->color->apply($text);
}
}
diff --git a/vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php b/vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php
index af171c270..b30560d22 100644
--- a/vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php
+++ b/vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php
@@ -20,31 +20,23 @@ interface OutputFormatterStyleInterface
{
/**
* Sets style foreground color.
- *
- * @param string|null $color The color name
*/
- public function setForeground($color = null);
+ public function setForeground(string $color = null);
/**
* Sets style background color.
- *
- * @param string $color The color name
*/
- public function setBackground($color = null);
+ public function setBackground(string $color = null);
/**
* Sets some specific style option.
- *
- * @param string $option The option name
*/
- public function setOption($option);
+ public function setOption(string $option);
/**
* Unsets some specific style option.
- *
- * @param string $option The option name
*/
- public function unsetOption($option);
+ public function unsetOption(string $option);
/**
* Sets multiple style options at once.
@@ -54,9 +46,7 @@ interface OutputFormatterStyleInterface
/**
* Applies the style to a given text.
*
- * @param string $text The text to style
- *
* @return string
*/
- public function apply($text);
+ public function apply(string $text);
}
diff --git a/vendor/symfony/console/Formatter/WrappableOutputFormatterInterface.php b/vendor/symfony/console/Formatter/WrappableOutputFormatterInterface.php
index 6694053f0..42319ee55 100644
--- a/vendor/symfony/console/Formatter/WrappableOutputFormatterInterface.php
+++ b/vendor/symfony/console/Formatter/WrappableOutputFormatterInterface.php
@@ -21,5 +21,5 @@ interface WrappableOutputFormatterInterface extends OutputFormatterInterface
/**
* Formats a message according to the given styles, wrapping at `$width` (0 means no wrapping).
*/
- public function formatAndWrap(string $message, int $width);
+ public function formatAndWrap(?string $message, int $width);
}
diff --git a/vendor/symfony/console/Helper/DebugFormatterHelper.php b/vendor/symfony/console/Helper/DebugFormatterHelper.php
index 1653edeb1..e258ba050 100644
--- a/vendor/symfony/console/Helper/DebugFormatterHelper.php
+++ b/vendor/symfony/console/Helper/DebugFormatterHelper.php
@@ -20,22 +20,18 @@ namespace Symfony\Component\Console\Helper;
*/
class DebugFormatterHelper extends Helper
{
- private $colors = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', 'default'];
+ private const COLORS = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', 'default'];
private $started = [];
private $count = -1;
/**
* Starts a debug formatting session.
*
- * @param string $id The id of the formatting session
- * @param string $message The message to display
- * @param string $prefix The prefix to use
- *
* @return string
*/
- public function start($id, $message, $prefix = 'RUN')
+ public function start(string $id, string $message, string $prefix = 'RUN')
{
- $this->started[$id] = ['border' => ++$this->count % \count($this->colors)];
+ $this->started[$id] = ['border' => ++$this->count % \count(self::COLORS)];
return sprintf("%s %s > %s>\n", $this->getBorder($id), $prefix, $message);
}
@@ -43,15 +39,9 @@ class DebugFormatterHelper extends Helper
/**
* Adds progress to a formatting session.
*
- * @param string $id The id of the formatting session
- * @param string $buffer The message to display
- * @param bool $error Whether to consider the buffer as error
- * @param string $prefix The prefix for output
- * @param string $errorPrefix The prefix for error output
- *
* @return string
*/
- public function progress($id, $buffer, $error = false, $prefix = 'OUT', $errorPrefix = 'ERR')
+ public function progress(string $id, string $buffer, bool $error = false, string $prefix = 'OUT', string $errorPrefix = 'ERR')
{
$message = '';
@@ -85,14 +75,9 @@ class DebugFormatterHelper extends Helper
/**
* Stops a formatting session.
*
- * @param string $id The id of the formatting session
- * @param string $message The message to display
- * @param bool $successful Whether to consider the result as success
- * @param string $prefix The prefix for the end output
- *
* @return string
*/
- public function stop($id, $message, $successful, $prefix = 'RES')
+ public function stop(string $id, string $message, bool $successful, string $prefix = 'RES')
{
$trailingEOL = isset($this->started[$id]['out']) || isset($this->started[$id]['err']) ? "\n" : '';
@@ -109,7 +94,7 @@ class DebugFormatterHelper extends Helper
private function getBorder(string $id): string
{
- return sprintf(' >', $this->colors[$this->started[$id]['border']]);
+ return sprintf(' >', self::COLORS[$this->started[$id]['border']]);
}
/**
diff --git a/vendor/symfony/console/Helper/DescriptorHelper.php b/vendor/symfony/console/Helper/DescriptorHelper.php
index 3055baefd..af85e9c0a 100644
--- a/vendor/symfony/console/Helper/DescriptorHelper.php
+++ b/vendor/symfony/console/Helper/DescriptorHelper.php
@@ -48,11 +48,9 @@ class DescriptorHelper extends Helper
* * format: string, the output format name
* * raw_text: boolean, sets output type as raw
*
- * @param object $object
- *
* @throws InvalidArgumentException when the given format is not supported
*/
- public function describe(OutputInterface $output, $object, array $options = [])
+ public function describe(OutputInterface $output, ?object $object, array $options = [])
{
$options = array_merge([
'raw_text' => false,
@@ -70,11 +68,9 @@ class DescriptorHelper extends Helper
/**
* Registers a descriptor.
*
- * @param string $format
- *
* @return $this
*/
- public function register($format, DescriptorInterface $descriptor)
+ public function register(string $format, DescriptorInterface $descriptor)
{
$this->descriptors[$format] = $descriptor;
@@ -88,4 +84,9 @@ class DescriptorHelper extends Helper
{
return 'descriptor';
}
+
+ public function getFormats(): array
+ {
+ return array_keys($this->descriptors);
+ }
}
diff --git a/vendor/symfony/console/Helper/FormatterHelper.php b/vendor/symfony/console/Helper/FormatterHelper.php
index d6eccee8e..92d8dc724 100644
--- a/vendor/symfony/console/Helper/FormatterHelper.php
+++ b/vendor/symfony/console/Helper/FormatterHelper.php
@@ -23,13 +23,9 @@ class FormatterHelper extends Helper
/**
* Formats a message within a section.
*
- * @param string $section The section name
- * @param string $message The message
- * @param string $style The style to apply to the section
- *
- * @return string The format section
+ * @return string
*/
- public function formatSection($section, $message, $style = 'info')
+ public function formatSection(string $section, string $message, string $style = 'info')
{
return sprintf('<%s>[%s]%s> %s', $style, $section, $style, $message);
}
@@ -38,12 +34,10 @@ class FormatterHelper extends Helper
* Formats a message as a block of text.
*
* @param string|array $messages The message to write in the block
- * @param string $style The style to apply to the whole block
- * @param bool $large Whether to return a large block
*
- * @return string The formatter message
+ * @return string
*/
- public function formatBlock($messages, $style, $large = false)
+ public function formatBlock($messages, string $style, bool $large = false)
{
if (!\is_array($messages)) {
$messages = [$messages];
@@ -54,12 +48,12 @@ class FormatterHelper extends Helper
foreach ($messages as $message) {
$message = OutputFormatter::escape($message);
$lines[] = sprintf($large ? ' %s ' : ' %s ', $message);
- $len = max(self::strlen($message) + ($large ? 4 : 2), $len);
+ $len = max(self::width($message) + ($large ? 4 : 2), $len);
}
$messages = $large ? [str_repeat(' ', $len)] : [];
for ($i = 0; isset($lines[$i]); ++$i) {
- $messages[] = $lines[$i].str_repeat(' ', $len - self::strlen($lines[$i]));
+ $messages[] = $lines[$i].str_repeat(' ', $len - self::width($lines[$i]));
}
if ($large) {
$messages[] = str_repeat(' ', $len);
@@ -75,17 +69,13 @@ class FormatterHelper extends Helper
/**
* Truncates a message to the given length.
*
- * @param string $message
- * @param int $length
- * @param string $suffix
- *
* @return string
*/
- public function truncate($message, $length, $suffix = '...')
+ public function truncate(string $message, int $length, string $suffix = '...')
{
- $computedLength = $length - self::strlen($suffix);
+ $computedLength = $length - self::width($suffix);
- if ($computedLength > self::strlen($message)) {
+ if ($computedLength > self::width($message)) {
return $message;
}
diff --git a/vendor/symfony/console/Helper/Helper.php b/vendor/symfony/console/Helper/Helper.php
index 0521aaf7d..c7d3e25d0 100644
--- a/vendor/symfony/console/Helper/Helper.php
+++ b/vendor/symfony/console/Helper/Helper.php
@@ -12,6 +12,7 @@
namespace Symfony\Component\Console\Helper;
use Symfony\Component\Console\Formatter\OutputFormatterInterface;
+use Symfony\Component\String\UnicodeString;
/**
* Helper is the base class for all helper classes.
@@ -41,13 +42,28 @@ abstract class Helper implements HelperInterface
/**
* Returns the length of a string, using mb_strwidth if it is available.
*
- * @param string $string The string to check its length
+ * @deprecated since Symfony 5.3
*
- * @return int The length of the string
+ * @return int
*/
- public static function strlen($string)
+ public static function strlen(?string $string)
{
- $string = (string) $string;
+ trigger_deprecation('symfony/console', '5.3', 'Method "%s()" is deprecated and will be removed in Symfony 6.0. Use Helper::width() or Helper::length() instead.', __METHOD__);
+
+ return self::width($string);
+ }
+
+ /**
+ * Returns the width of a string, using mb_strwidth if it is available.
+ * The width is how many characters positions the string will use.
+ */
+ public static function width(?string $string): int
+ {
+ $string ?? $string = '';
+
+ if (preg_match('//u', $string)) {
+ return (new UnicodeString($string))->width(false);
+ }
if (false === $encoding = mb_detect_encoding($string, null, true)) {
return \strlen($string);
@@ -56,18 +72,33 @@ abstract class Helper implements HelperInterface
return mb_strwidth($string, $encoding);
}
+ /**
+ * Returns the length of a string, using mb_strlen if it is available.
+ * The length is related to how many bytes the string will use.
+ */
+ public static function length(?string $string): int
+ {
+ $string ?? $string = '';
+
+ if (preg_match('//u', $string)) {
+ return (new UnicodeString($string))->length();
+ }
+
+ if (false === $encoding = mb_detect_encoding($string, null, true)) {
+ return \strlen($string);
+ }
+
+ return mb_strlen($string, $encoding);
+ }
+
/**
* Returns the subset of a string, using mb_substr if it is available.
*
- * @param string $string String to subset
- * @param int $from Start offset
- * @param int|null $length Length to read
- *
- * @return string The string subset
+ * @return string
*/
- public static function substr($string, $from, $length = null)
+ public static function substr(?string $string, int $from, int $length = null)
{
- $string = (string) $string;
+ $string ?? $string = '';
if (false === $encoding = mb_detect_encoding($string, null, true)) {
return substr($string, $from, $length);
@@ -105,7 +136,7 @@ abstract class Helper implements HelperInterface
}
}
- public static function formatMemory($memory)
+ public static function formatMemory(int $memory)
{
if ($memory >= 1024 * 1024 * 1024) {
return sprintf('%.1f GiB', $memory / 1024 / 1024 / 1024);
@@ -122,19 +153,26 @@ abstract class Helper implements HelperInterface
return sprintf('%d B', $memory);
}
- public static function strlenWithoutDecoration(OutputFormatterInterface $formatter, $string)
+ /**
+ * @deprecated since Symfony 5.3
+ */
+ public static function strlenWithoutDecoration(OutputFormatterInterface $formatter, ?string $string)
{
- return self::strlen(self::removeDecoration($formatter, $string));
+ trigger_deprecation('symfony/console', '5.3', 'Method "%s()" is deprecated and will be removed in Symfony 6.0. Use Helper::removeDecoration() instead.', __METHOD__);
+
+ return self::width(self::removeDecoration($formatter, $string));
}
- public static function removeDecoration(OutputFormatterInterface $formatter, $string)
+ public static function removeDecoration(OutputFormatterInterface $formatter, ?string $string)
{
$isDecorated = $formatter->isDecorated();
$formatter->setDecorated(false);
// remove <...> formatting
- $string = $formatter->format($string);
+ $string = $formatter->format($string ?? '');
// remove already formatted characters
- $string = preg_replace("/\033\[[^m]*m/", '', $string);
+ $string = preg_replace("/\033\[[^m]*m/", '', $string ?? '');
+ // remove terminal hyperlinks
+ $string = preg_replace('/\\033]8;[^;]*;[^\\033]*\\033\\\\/', '', $string ?? '');
$formatter->setDecorated($isDecorated);
return $string;
diff --git a/vendor/symfony/console/Helper/HelperInterface.php b/vendor/symfony/console/Helper/HelperInterface.php
index 1ce823587..fc952b486 100644
--- a/vendor/symfony/console/Helper/HelperInterface.php
+++ b/vendor/symfony/console/Helper/HelperInterface.php
@@ -26,14 +26,14 @@ interface HelperInterface
/**
* Gets the helper set associated with this helper.
*
- * @return HelperSet A HelperSet instance
+ * @return HelperSet|null
*/
public function getHelperSet();
/**
* Returns the canonical name of this helper.
*
- * @return string The canonical name
+ * @return string
*/
public function getName();
}
diff --git a/vendor/symfony/console/Helper/HelperSet.php b/vendor/symfony/console/Helper/HelperSet.php
index 9aa1e67ba..719762d24 100644
--- a/vendor/symfony/console/Helper/HelperSet.php
+++ b/vendor/symfony/console/Helper/HelperSet.php
@@ -18,12 +18,12 @@ use Symfony\Component\Console\Exception\InvalidArgumentException;
* HelperSet represents a set of helpers to be used with a command.
*
* @author Fabien Potencier
+ *
+ * @implements \IteratorAggregate
*/
class HelperSet implements \IteratorAggregate
{
- /**
- * @var Helper[]
- */
+ /** @var array */
private $helpers = [];
private $command;
@@ -37,12 +37,7 @@ class HelperSet implements \IteratorAggregate
}
}
- /**
- * Sets a helper.
- *
- * @param string $alias An alias
- */
- public function set(HelperInterface $helper, $alias = null)
+ public function set(HelperInterface $helper, string $alias = null)
{
$this->helpers[$helper->getName()] = $helper;
if (null !== $alias) {
@@ -55,11 +50,9 @@ class HelperSet implements \IteratorAggregate
/**
* Returns true if the helper if defined.
*
- * @param string $name The helper name
- *
- * @return bool true if the helper is defined, false otherwise
+ * @return bool
*/
- public function has($name)
+ public function has(string $name)
{
return isset($this->helpers[$name]);
}
@@ -67,13 +60,11 @@ class HelperSet implements \IteratorAggregate
/**
* Gets a helper value.
*
- * @param string $name The helper name
- *
- * @return HelperInterface The helper instance
+ * @return HelperInterface
*
* @throws InvalidArgumentException if the helper is not defined
*/
- public function get($name)
+ public function get(string $name)
{
if (!$this->has($name)) {
throw new InvalidArgumentException(sprintf('The helper "%s" is not defined.', $name));
@@ -82,23 +73,32 @@ class HelperSet implements \IteratorAggregate
return $this->helpers[$name];
}
+ /**
+ * @deprecated since Symfony 5.4
+ */
public function setCommand(Command $command = null)
{
+ trigger_deprecation('symfony/console', '5.4', 'Method "%s()" is deprecated.', __METHOD__);
+
$this->command = $command;
}
/**
* Gets the command associated with this helper set.
*
- * @return Command A Command instance
+ * @return Command
+ *
+ * @deprecated since Symfony 5.4
*/
public function getCommand()
{
+ trigger_deprecation('symfony/console', '5.4', 'Method "%s()" is deprecated.', __METHOD__);
+
return $this->command;
}
/**
- * @return \Traversable
+ * @return \Traversable
*/
#[\ReturnTypeWillChange]
public function getIterator()
diff --git a/vendor/symfony/console/Helper/ProcessHelper.php b/vendor/symfony/console/Helper/ProcessHelper.php
index 862d09f21..4ea3d724d 100644
--- a/vendor/symfony/console/Helper/ProcessHelper.php
+++ b/vendor/symfony/console/Helper/ProcessHelper.php
@@ -21,22 +21,18 @@ use Symfony\Component\Process\Process;
*
* @author Fabien Potencier
*
- * @final since Symfony 4.2
+ * @final
*/
class ProcessHelper extends Helper
{
/**
* Runs an external process.
*
- * @param array|Process $cmd An instance of Process or an array of the command and arguments
- * @param string|null $error An error message that must be displayed if something went wrong
- * @param callable|null $callback A PHP callback to run whenever there is some
- * output available on STDOUT or STDERR
- * @param int $verbosity The threshold for verbosity
- *
- * @return Process The process that ran
+ * @param array|Process $cmd An instance of Process or an array of the command and arguments
+ * @param callable|null $callback A PHP callback to run whenever there is some
+ * output available on STDOUT or STDERR
*/
- public function run(OutputInterface $output, $cmd, $error = null, callable $callback = null, $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE)
+ public function run(OutputInterface $output, $cmd, string $error = null, callable $callback = null, int $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE): Process
{
if (!class_exists(Process::class)) {
throw new \LogicException('The ProcessHelper cannot be run as the Process component is not installed. Try running "compose require symfony/process".');
@@ -53,8 +49,7 @@ class ProcessHelper extends Helper
}
if (!\is_array($cmd)) {
- @trigger_error(sprintf('Passing a command as a string to "%s()" is deprecated since Symfony 4.2, pass it the command as an array of arguments instead.', __METHOD__), \E_USER_DEPRECATED);
- $cmd = [method_exists(Process::class, 'fromShellCommandline') ? Process::fromShellCommandline($cmd) : new Process($cmd)];
+ throw new \TypeError(sprintf('The "command" argument of "%s()" must be an array or a "%s" instance, "%s" given.', __METHOD__, Process::class, get_debug_type($cmd)));
}
if (\is_string($cmd[0] ?? null)) {
@@ -96,17 +91,14 @@ class ProcessHelper extends Helper
* exits with a non-zero exit code.
*
* @param array|Process $cmd An instance of Process or a command to run
- * @param string|null $error An error message that must be displayed if something went wrong
* @param callable|null $callback A PHP callback to run whenever there is some
* output available on STDOUT or STDERR
*
- * @return Process The process that ran
- *
* @throws ProcessFailedException
*
* @see run()
*/
- public function mustRun(OutputInterface $output, $cmd, $error = null, callable $callback = null)
+ public function mustRun(OutputInterface $output, $cmd, string $error = null, callable $callback = null): Process
{
$process = $this->run($output, $cmd, $error, $callback);
@@ -119,10 +111,8 @@ class ProcessHelper extends Helper
/**
* Wraps a Process callback to add debugging output.
- *
- * @return callable
*/
- public function wrapCallback(OutputInterface $output, Process $process, callable $callback = null)
+ public function wrapCallback(OutputInterface $output, Process $process, callable $callback = null): callable
{
if ($output instanceof ConsoleOutputInterface) {
$output = $output->getErrorOutput();
@@ -147,7 +137,7 @@ class ProcessHelper extends Helper
/**
* {@inheritdoc}
*/
- public function getName()
+ public function getName(): string
{
return 'process';
}
diff --git a/vendor/symfony/console/Helper/ProgressBar.php b/vendor/symfony/console/Helper/ProgressBar.php
index 1de9b7b3c..eb6aacb1a 100644
--- a/vendor/symfony/console/Helper/ProgressBar.php
+++ b/vendor/symfony/console/Helper/ProgressBar.php
@@ -11,6 +11,7 @@
namespace Symfony\Component\Console\Helper;
+use Symfony\Component\Console\Cursor;
use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\ConsoleSectionOutput;
@@ -25,6 +26,16 @@ use Symfony\Component\Console\Terminal;
*/
final class ProgressBar
{
+ public const FORMAT_VERBOSE = 'verbose';
+ public const FORMAT_VERY_VERBOSE = 'very_verbose';
+ public const FORMAT_DEBUG = 'debug';
+ public const FORMAT_NORMAL = 'normal';
+
+ private const FORMAT_VERBOSE_NOMAX = 'verbose_nomax';
+ private const FORMAT_VERY_VERBOSE_NOMAX = 'very_verbose_nomax';
+ private const FORMAT_DEBUG_NOMAX = 'debug_nomax';
+ private const FORMAT_NORMAL_NOMAX = 'normal_nomax';
+
private $barWidth = 28;
private $barChar;
private $emptyBarChar = '-';
@@ -42,11 +53,11 @@ final class ProgressBar
private $startTime;
private $stepWidth;
private $percent = 0.0;
- private $formatLineCount;
private $messages = [];
private $overwrite = true;
private $terminal;
private $previousMessage;
+ private $cursor;
private static $formatters;
private static $formats;
@@ -54,7 +65,7 @@ final class ProgressBar
/**
* @param int $max Maximum steps (0 if unknown)
*/
- public function __construct(OutputInterface $output, int $max = 0, float $minSecondsBetweenRedraws = 0.1)
+ public function __construct(OutputInterface $output, int $max = 0, float $minSecondsBetweenRedraws = 1 / 25)
{
if ($output instanceof ConsoleOutputInterface) {
$output = $output->getErrorOutput();
@@ -78,6 +89,7 @@ final class ProgressBar
}
$this->startTime = time();
+ $this->cursor = new Cursor($output);
}
/**
@@ -101,8 +113,6 @@ final class ProgressBar
* Gets the placeholder formatter for a given name.
*
* @param string $name The placeholder name (including the delimiter char like %)
- *
- * @return callable|null A PHP callable
*/
public static function getPlaceholderFormatterDefinition(string $name): ?callable
{
@@ -134,8 +144,6 @@ final class ProgressBar
* Gets the format for a given name.
*
* @param string $name The format name
- *
- * @return string|null A format string
*/
public static function getFormatDefinition(string $name): ?string
{
@@ -191,11 +199,29 @@ final class ProgressBar
return $this->percent;
}
- public function getBarOffset(): int
+ public function getBarOffset(): float
{
return floor($this->max ? $this->percent * $this->barWidth : (null === $this->redrawFreq ? (int) (min(5, $this->barWidth / 15) * $this->writeCount) : $this->step) % $this->barWidth);
}
+ public function getEstimated(): float
+ {
+ if (!$this->step) {
+ return 0;
+ }
+
+ return round((time() - $this->startTime) / $this->step * $this->max);
+ }
+
+ public function getRemaining(): float
+ {
+ if (!$this->step) {
+ return 0;
+ }
+
+ return round((time() - $this->startTime) / $this->step * ($this->max - $this->step));
+ }
+
public function setBarWidth(int $size)
{
$this->barWidth = max(1, $size);
@@ -213,11 +239,7 @@ final class ProgressBar
public function getBarCharacter(): string
{
- if (null === $this->barChar) {
- return $this->max ? '=' : $this->emptyBarChar;
- }
-
- return $this->barChar;
+ return $this->barChar ?? ($this->max ? '=' : $this->emptyBarChar);
}
public function setEmptyBarCharacter(string $char)
@@ -357,7 +379,7 @@ final class ProgressBar
{
$this->format = null;
$this->max = max(0, $max);
- $this->stepWidth = $this->max ? Helper::strlen((string) $this->max) : 4;
+ $this->stepWidth = $this->max ? Helper::width((string) $this->max) : 4;
}
/**
@@ -423,8 +445,6 @@ final class ProgressBar
} else {
$this->format = $format;
}
-
- $this->formatLineCount = substr_count($this->format, "\n");
}
/**
@@ -441,23 +461,25 @@ final class ProgressBar
if ($this->overwrite) {
if (null !== $this->previousMessage) {
if ($this->output instanceof ConsoleSectionOutput) {
- $messageLines = explode("\n", $message);
+ $messageLines = explode("\n", $this->previousMessage);
$lineCount = \count($messageLines);
foreach ($messageLines as $messageLine) {
- $messageLineLength = Helper::strlenWithoutDecoration($this->output->getFormatter(), $messageLine);
+ $messageLineLength = Helper::width(Helper::removeDecoration($this->output->getFormatter(), $messageLine));
if ($messageLineLength > $this->terminal->getWidth()) {
$lineCount += floor($messageLineLength / $this->terminal->getWidth());
}
}
$this->output->clear($lineCount);
} else {
- // Erase previous lines
- if ($this->formatLineCount > 0) {
- $message = str_repeat("\x1B[1A\x1B[2K", $this->formatLineCount).$message;
+ $lineCount = substr_count($this->previousMessage, "\n");
+ for ($i = 0; $i < $lineCount; ++$i) {
+ $this->cursor->moveToColumn(1);
+ $this->cursor->clearLine();
+ $this->cursor->moveUp();
}
- // Move the cursor to the beginning of the line and erase the line
- $message = "\x0D\x1B[2K$message";
+ $this->cursor->moveToColumn(1);
+ $this->cursor->clearLine();
}
}
} elseif ($this->step > 0) {
@@ -476,13 +498,13 @@ final class ProgressBar
switch ($this->output->getVerbosity()) {
// OutputInterface::VERBOSITY_QUIET: display is disabled anyway
case OutputInterface::VERBOSITY_VERBOSE:
- return $this->max ? 'verbose' : 'verbose_nomax';
+ return $this->max ? self::FORMAT_VERBOSE : self::FORMAT_VERBOSE_NOMAX;
case OutputInterface::VERBOSITY_VERY_VERBOSE:
- return $this->max ? 'very_verbose' : 'very_verbose_nomax';
+ return $this->max ? self::FORMAT_VERY_VERBOSE : self::FORMAT_VERY_VERBOSE_NOMAX;
case OutputInterface::VERBOSITY_DEBUG:
- return $this->max ? 'debug' : 'debug_nomax';
+ return $this->max ? self::FORMAT_DEBUG : self::FORMAT_DEBUG_NOMAX;
default:
- return $this->max ? 'normal' : 'normal_nomax';
+ return $this->max ? self::FORMAT_NORMAL : self::FORMAT_NORMAL_NOMAX;
}
}
@@ -493,7 +515,7 @@ final class ProgressBar
$completeBars = $bar->getBarOffset();
$display = str_repeat($bar->getBarCharacter(), $completeBars);
if ($completeBars < $bar->getBarWidth()) {
- $emptyBars = $bar->getBarWidth() - $completeBars - Helper::strlenWithoutDecoration($output->getFormatter(), $bar->getProgressCharacter());
+ $emptyBars = $bar->getBarWidth() - $completeBars - Helper::length(Helper::removeDecoration($output->getFormatter(), $bar->getProgressCharacter()));
$display .= $bar->getProgressCharacter().str_repeat($bar->getEmptyBarCharacter(), $emptyBars);
}
@@ -507,26 +529,14 @@ final class ProgressBar
throw new LogicException('Unable to display the remaining time if the maximum number of steps is not set.');
}
- if (!$bar->getProgress()) {
- $remaining = 0;
- } else {
- $remaining = round((time() - $bar->getStartTime()) / $bar->getProgress() * ($bar->getMaxSteps() - $bar->getProgress()));
- }
-
- return Helper::formatTime($remaining);
+ return Helper::formatTime($bar->getRemaining());
},
'estimated' => function (self $bar) {
if (!$bar->getMaxSteps()) {
throw new LogicException('Unable to display the estimated time if the maximum number of steps is not set.');
}
- if (!$bar->getProgress()) {
- $estimated = 0;
- } else {
- $estimated = round((time() - $bar->getStartTime()) / $bar->getProgress() * $bar->getMaxSteps());
- }
-
- return Helper::formatTime($estimated);
+ return Helper::formatTime($bar->getEstimated());
},
'memory' => function (self $bar) {
return Helper::formatMemory(memory_get_usage(true));
@@ -546,17 +556,17 @@ final class ProgressBar
private static function initFormats(): array
{
return [
- 'normal' => ' %current%/%max% [%bar%] %percent:3s%%',
- 'normal_nomax' => ' %current% [%bar%]',
+ self::FORMAT_NORMAL => ' %current%/%max% [%bar%] %percent:3s%%',
+ self::FORMAT_NORMAL_NOMAX => ' %current% [%bar%]',
- 'verbose' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%',
- 'verbose_nomax' => ' %current% [%bar%] %elapsed:6s%',
+ self::FORMAT_VERBOSE => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%',
+ self::FORMAT_VERBOSE_NOMAX => ' %current% [%bar%] %elapsed:6s%',
- 'very_verbose' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%',
- 'very_verbose_nomax' => ' %current% [%bar%] %elapsed:6s%',
+ self::FORMAT_VERY_VERBOSE => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%',
+ self::FORMAT_VERY_VERBOSE_NOMAX => ' %current% [%bar%] %elapsed:6s%',
- 'debug' => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%',
- 'debug_nomax' => ' %current% [%bar%] %elapsed:6s% %memory:6s%',
+ self::FORMAT_DEBUG => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%',
+ self::FORMAT_DEBUG_NOMAX => ' %current% [%bar%] %elapsed:6s% %memory:6s%',
];
}
@@ -582,7 +592,7 @@ final class ProgressBar
// gets string length for each sub line with multiline format
$linesLength = array_map(function ($subLine) {
- return Helper::strlenWithoutDecoration($this->output->getFormatter(), rtrim($subLine, "\r"));
+ return Helper::width(Helper::removeDecoration($this->output->getFormatter(), rtrim($subLine, "\r")));
}, explode("\n", $line));
$linesWidth = max($linesLength);
diff --git a/vendor/symfony/console/Helper/ProgressIndicator.php b/vendor/symfony/console/Helper/ProgressIndicator.php
index dc37148ed..3482343fc 100644
--- a/vendor/symfony/console/Helper/ProgressIndicator.php
+++ b/vendor/symfony/console/Helper/ProgressIndicator.php
@@ -20,6 +20,17 @@ use Symfony\Component\Console\Output\OutputInterface;
*/
class ProgressIndicator
{
+ private const FORMATS = [
+ 'normal' => ' %indicator% %message%',
+ 'normal_no_ansi' => ' %message%',
+
+ 'verbose' => ' %indicator% %message% (%elapsed:6s%)',
+ 'verbose_no_ansi' => ' %message% (%elapsed:6s%)',
+
+ 'very_verbose' => ' %indicator% %message% (%elapsed:6s%, %memory:6s%)',
+ 'very_verbose_no_ansi' => ' %message% (%elapsed:6s%, %memory:6s%)',
+ ];
+
private $output;
private $startTime;
private $format;
@@ -30,13 +41,14 @@ class ProgressIndicator
private $indicatorUpdateTime;
private $started = false;
+ /**
+ * @var array
+ */
private static $formatters;
- private static $formats;
/**
- * @param string|null $format Indicator format
- * @param int $indicatorChangeInterval Change interval in milliseconds
- * @param array|null $indicatorValues Animated indicator characters
+ * @param int $indicatorChangeInterval Change interval in milliseconds
+ * @param array|null $indicatorValues Animated indicator characters
*/
public function __construct(OutputInterface $output, string $format = null, int $indicatorChangeInterval = 100, array $indicatorValues = null)
{
@@ -64,10 +76,8 @@ class ProgressIndicator
/**
* Sets the current indicator message.
- *
- * @param string|null $message
*/
- public function setMessage($message)
+ public function setMessage(?string $message)
{
$this->message = $message;
@@ -76,10 +86,8 @@ class ProgressIndicator
/**
* Starts the indicator output.
- *
- * @param $message
*/
- public function start($message)
+ public function start(string $message)
{
if ($this->started) {
throw new LogicException('Progress indicator already started.');
@@ -124,7 +132,7 @@ class ProgressIndicator
*
* @param $message
*/
- public function finish($message)
+ public function finish(string $message)
{
if (!$this->started) {
throw new LogicException('Progress indicator has not yet been started.');
@@ -139,28 +147,19 @@ class ProgressIndicator
/**
* Gets the format for a given name.
*
- * @param string $name The format name
- *
- * @return string|null A format string
+ * @return string|null
*/
- public static function getFormatDefinition($name)
+ public static function getFormatDefinition(string $name)
{
- if (!self::$formats) {
- self::$formats = self::initFormats();
- }
-
- return self::$formats[$name] ?? null;
+ return self::FORMATS[$name] ?? null;
}
/**
* Sets a placeholder formatter for a given name.
*
* This method also allow you to override an existing placeholder.
- *
- * @param string $name The placeholder name (including the delimiter char like %)
- * @param callable $callable A PHP callable
*/
- public static function setPlaceholderFormatterDefinition($name, $callable)
+ public static function setPlaceholderFormatterDefinition(string $name, callable $callable)
{
if (!self::$formatters) {
self::$formatters = self::initPlaceholderFormatters();
@@ -170,13 +169,11 @@ class ProgressIndicator
}
/**
- * Gets the placeholder formatter for a given name.
+ * Gets the placeholder formatter for a given name (including the delimiter char like %).
*
- * @param string $name The placeholder name (including the delimiter char like %)
- *
- * @return callable|null A PHP callable
+ * @return callable|null
*/
- public static function getPlaceholderFormatterDefinition($name)
+ public static function getPlaceholderFormatterDefinition(string $name)
{
if (!self::$formatters) {
self::$formatters = self::initPlaceholderFormatters();
@@ -249,18 +246,4 @@ class ProgressIndicator
},
];
}
-
- private static function initFormats(): array
- {
- return [
- 'normal' => ' %indicator% %message%',
- 'normal_no_ansi' => ' %message%',
-
- 'verbose' => ' %indicator% %message% (%elapsed:6s%)',
- 'verbose_no_ansi' => ' %message% (%elapsed:6s%)',
-
- 'very_verbose' => ' %indicator% %message% (%elapsed:6s%, %memory:6s%)',
- 'very_verbose_no_ansi' => ' %message% (%elapsed:6s%, %memory:6s%)',
- ];
- }
}
diff --git a/vendor/symfony/console/Helper/QuestionHelper.php b/vendor/symfony/console/Helper/QuestionHelper.php
index a4754b824..e236be92a 100644
--- a/vendor/symfony/console/Helper/QuestionHelper.php
+++ b/vendor/symfony/console/Helper/QuestionHelper.php
@@ -11,6 +11,7 @@
namespace Symfony\Component\Console\Helper;
+use Symfony\Component\Console\Cursor;
use Symfony\Component\Console\Exception\MissingInputException;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Formatter\OutputFormatter;
@@ -24,6 +25,8 @@ use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Terminal;
+use function Symfony\Component\String\s;
+
/**
* The QuestionHelper class provides helpers to interact with the user.
*
@@ -31,8 +34,11 @@ use Symfony\Component\Console\Terminal;
*/
class QuestionHelper extends Helper
{
+ /**
+ * @var resource|null
+ */
private $inputStream;
- private static $shell;
+
private static $stty = true;
private static $stdinIsInteractive;
@@ -122,9 +128,18 @@ class QuestionHelper extends Helper
}
if (false === $ret) {
- $cp = $this->setIOCodepage();
- $ret = fgets($inputStream, 4096);
- $ret = $this->resetIOCodepage($cp, $ret);
+ $isBlocked = stream_get_meta_data($inputStream)['blocked'] ?? true;
+
+ if (!$isBlocked) {
+ stream_set_blocking($inputStream, true);
+ }
+
+ $ret = $this->readInput($inputStream, $question);
+
+ if (!$isBlocked) {
+ stream_set_blocking($inputStream, false);
+ }
+
if (false === $ret) {
throw new MissingInputException('Aborted.');
}
@@ -199,18 +214,16 @@ class QuestionHelper extends Helper
}
/**
- * @param string $tag
- *
* @return string[]
*/
- protected function formatChoiceQuestionChoices(ChoiceQuestion $question, $tag)
+ protected function formatChoiceQuestionChoices(ChoiceQuestion $question, string $tag)
{
$messages = [];
- $maxWidth = max(array_map([__CLASS__, 'strlen'], array_keys($choices = $question->getChoices())));
+ $maxWidth = max(array_map([__CLASS__, 'width'], array_keys($choices = $question->getChoices())));
foreach ($choices as $key => $value) {
- $padding = str_repeat(' ', $maxWidth - self::strlen($key));
+ $padding = str_repeat(' ', $maxWidth - self::width($key));
$messages[] = sprintf(" [<$tag>%s$padding$tag>] %s", $key, $value);
}
@@ -239,6 +252,8 @@ class QuestionHelper extends Helper
*/
private function autocomplete(OutputInterface $output, Question $question, $inputStream, callable $autocomplete): string
{
+ $cursor = new Cursor($output, $inputStream);
+
$fullChoice = '';
$ret = '';
@@ -248,6 +263,9 @@ class QuestionHelper extends Helper
$numMatches = \count($matches);
$sttyMode = shell_exec('stty -g');
+ $isStdin = 'php://stdin' === (stream_get_meta_data($inputStream)['uri'] ?? null);
+ $r = [$inputStream];
+ $w = [];
// Disable icanon (so we can fread each keypress) and echo (we'll do echoing here instead)
shell_exec('stty -icanon -echo');
@@ -257,18 +275,22 @@ class QuestionHelper extends Helper
// Read a keypress
while (!feof($inputStream)) {
+ while ($isStdin && 0 === @stream_select($r, $w, $w, 0, 100)) {
+ // Give signal handlers a chance to run
+ $r = [$inputStream];
+ }
$c = fread($inputStream, 1);
// as opposed to fgets(), fread() returns an empty string when the stream content is empty, not false.
if (false === $c || ('' === $ret && '' === $c && null === $question->getDefault())) {
- shell_exec(sprintf('stty %s', $sttyMode));
+ shell_exec('stty '.$sttyMode);
throw new MissingInputException('Aborted.');
} elseif ("\177" === $c) { // Backspace Character
if (0 === $numMatches && 0 !== $i) {
--$i;
+ $cursor->moveLeft(s($fullChoice)->slice(-1)->width(false));
+
$fullChoice = self::substr($fullChoice, 0, $i);
- // Move cursor backwards
- $output->write("\033[1D");
}
if (0 === $i) {
@@ -354,22 +376,19 @@ class QuestionHelper extends Helper
}
}
- // Erase characters from cursor to end of line
- $output->write("\033[K");
+ $cursor->clearLineAfter();
if ($numMatches > 0 && -1 !== $ofs) {
- // Save cursor position
- $output->write("\0337");
+ $cursor->savePosition();
// Write highlighted text, complete the partially entered response
$charactersEntered = \strlen(trim($this->mostRecentlyEnteredValue($fullChoice)));
$output->write(''.OutputFormatter::escapeTrailingBackslash(substr($matches[$ofs], $charactersEntered)).'');
- // Restore cursor position
- $output->write("\0338");
+ $cursor->restorePosition();
}
}
// Reset stty so it behaves normally again
- shell_exec(sprintf('stty %s', $sttyMode));
+ shell_exec('stty '.$sttyMode);
return $fullChoice;
}
@@ -430,7 +449,7 @@ class QuestionHelper extends Helper
$value = fgets($inputStream, 4096);
if (self::$stty && Terminal::hasSttyAvailable()) {
- shell_exec(sprintf('stty %s', $sttyMode));
+ shell_exec('stty '.$sttyMode);
}
if (false === $value) {
@@ -492,13 +511,45 @@ class QuestionHelper extends Helper
return self::$stdinIsInteractive = @posix_isatty(fopen('php://stdin', 'r'));
}
- if (!\function_exists('exec')) {
+ if (!\function_exists('shell_exec')) {
return self::$stdinIsInteractive = true;
}
- exec('stty 2> /dev/null', $output, $status);
+ return self::$stdinIsInteractive = (bool) shell_exec('stty 2> '.('\\' === \DIRECTORY_SEPARATOR ? 'NUL' : '/dev/null'));
+ }
- return self::$stdinIsInteractive = 1 !== $status;
+ /**
+ * Reads one or more lines of input and returns what is read.
+ *
+ * @param resource $inputStream The handler resource
+ * @param Question $question The question being asked
+ *
+ * @return string|false The input received, false in case input could not be read
+ */
+ private function readInput($inputStream, Question $question)
+ {
+ if (!$question->isMultiline()) {
+ $cp = $this->setIOCodepage();
+ $ret = fgets($inputStream, 4096);
+
+ return $this->resetIOCodepage($cp, $ret);
+ }
+
+ $multiLineStreamReader = $this->cloneInputStream($inputStream);
+ if (null === $multiLineStreamReader) {
+ return false;
+ }
+
+ $ret = '';
+ $cp = $this->setIOCodepage();
+ while (false !== ($char = fgetc($multiLineStreamReader))) {
+ if (\PHP_EOL === "{$ret}{$char}") {
+ break;
+ }
+ $ret .= $char;
+ }
+
+ return $this->resetIOCodepage($cp, $ret);
}
/**
@@ -537,4 +588,38 @@ class QuestionHelper extends Helper
return $input;
}
+
+ /**
+ * Clones an input stream in order to act on one instance of the same
+ * stream without affecting the other instance.
+ *
+ * @param resource $inputStream The handler resource
+ *
+ * @return resource|null The cloned resource, null in case it could not be cloned
+ */
+ private function cloneInputStream($inputStream)
+ {
+ $streamMetaData = stream_get_meta_data($inputStream);
+ $seekable = $streamMetaData['seekable'] ?? false;
+ $mode = $streamMetaData['mode'] ?? 'rb';
+ $uri = $streamMetaData['uri'] ?? null;
+
+ if (null === $uri) {
+ return null;
+ }
+
+ $cloneStream = fopen($uri, $mode);
+
+ // For seekable and writable streams, add all the same data to the
+ // cloned stream and then seek to the same offset.
+ if (true === $seekable && !\in_array($mode, ['r', 'rb', 'rt'])) {
+ $offset = ftell($inputStream);
+ rewind($inputStream);
+ stream_copy_to_stream($inputStream, $cloneStream);
+ fseek($inputStream, $offset);
+ fseek($cloneStream, $offset);
+ }
+
+ return $cloneStream;
+ }
}
diff --git a/vendor/symfony/console/Helper/SymfonyQuestionHelper.php b/vendor/symfony/console/Helper/SymfonyQuestionHelper.php
index ace5e1868..01f94aba4 100644
--- a/vendor/symfony/console/Helper/SymfonyQuestionHelper.php
+++ b/vendor/symfony/console/Helper/SymfonyQuestionHelper.php
@@ -33,6 +33,10 @@ class SymfonyQuestionHelper extends QuestionHelper
$text = OutputFormatter::escapeTrailingBackslash($question->getQuestion());
$default = $question->getDefault();
+ if ($question->isMultiline()) {
+ $text .= sprintf(' (press %s to continue)', $this->getEofShortcut());
+ }
+
switch (true) {
case null === $default:
$text = sprintf(' %s:', $text);
@@ -93,4 +97,13 @@ class SymfonyQuestionHelper extends QuestionHelper
parent::writeError($output, $error);
}
+
+ private function getEofShortcut(): string
+ {
+ if ('Windows' === \PHP_OS_FAMILY) {
+ return 'Ctrl+Z then Enter';
+ }
+
+ return 'Ctrl+D';
+ }
}
diff --git a/vendor/symfony/console/Helper/Table.php b/vendor/symfony/console/Helper/Table.php
index 1d0a22baa..5c3447ab3 100644
--- a/vendor/symfony/console/Helper/Table.php
+++ b/vendor/symfony/console/Helper/Table.php
@@ -85,6 +85,9 @@ class Table
private $columnWidths = [];
private $columnMaxWidths = [];
+ /**
+ * @var array|null
+ */
private static $styles;
private $rendered = false;
@@ -102,10 +105,8 @@ class Table
/**
* Sets a style definition.
- *
- * @param string $name The style name
*/
- public static function setStyleDefinition($name, TableStyle $style)
+ public static function setStyleDefinition(string $name, TableStyle $style)
{
if (!self::$styles) {
self::$styles = self::initStyles();
@@ -117,11 +118,9 @@ class Table
/**
* Gets a style definition by name.
*
- * @param string $name The style name
- *
* @return TableStyle
*/
- public static function getStyleDefinition($name)
+ public static function getStyleDefinition(string $name)
{
if (!self::$styles) {
self::$styles = self::initStyles();
@@ -161,15 +160,12 @@ class Table
/**
* Sets table column style.
*
- * @param int $columnIndex Column index
- * @param TableStyle|string $name The style name or a TableStyle instance
+ * @param TableStyle|string $name The style name or a TableStyle instance
*
* @return $this
*/
- public function setColumnStyle($columnIndex, $name)
+ public function setColumnStyle(int $columnIndex, $name)
{
- $columnIndex = (int) $columnIndex;
-
$this->columnStyles[$columnIndex] = $this->resolveStyle($name);
return $this;
@@ -180,11 +176,9 @@ class Table
*
* If style was not set, it returns the global table style.
*
- * @param int $columnIndex Column index
- *
* @return TableStyle
*/
- public function getColumnStyle($columnIndex)
+ public function getColumnStyle(int $columnIndex)
{
return $this->columnStyles[$columnIndex] ?? $this->getStyle();
}
@@ -192,14 +186,11 @@ class Table
/**
* Sets the minimum width of a column.
*
- * @param int $columnIndex Column index
- * @param int $width Minimum column width in characters
- *
* @return $this
*/
- public function setColumnWidth($columnIndex, $width)
+ public function setColumnWidth(int $columnIndex, int $width)
{
- $this->columnWidths[(int) $columnIndex] = (int) $width;
+ $this->columnWidths[$columnIndex] = $width;
return $this;
}
@@ -230,7 +221,7 @@ class Table
public function setColumnMaxWidth(int $columnIndex, int $width): self
{
if (!$this->output->getFormatter() instanceof WrappableOutputFormatterInterface) {
- throw new \LogicException(sprintf('Setting a maximum column width is only supported when using a "%s" formatter, got "%s".', WrappableOutputFormatterInterface::class, \get_class($this->output->getFormatter())));
+ throw new \LogicException(sprintf('Setting a maximum column width is only supported when using a "%s" formatter, got "%s".', WrappableOutputFormatterInterface::class, get_debug_type($this->output->getFormatter())));
}
$this->columnMaxWidths[$columnIndex] = $width;
@@ -238,6 +229,9 @@ class Table
return $this;
}
+ /**
+ * @return $this
+ */
public function setHeaders(array $headers)
{
$headers = array_values($headers);
@@ -257,6 +251,9 @@ class Table
return $this->addRows($rows);
}
+ /**
+ * @return $this
+ */
public function addRows(array $rows)
{
foreach ($rows as $row) {
@@ -266,6 +263,9 @@ class Table
return $this;
}
+ /**
+ * @return $this
+ */
public function addRow($row)
{
if ($row instanceof TableSeparator) {
@@ -285,6 +285,8 @@ class Table
/**
* Adds a row to the table, and re-renders the table.
+ *
+ * @return $this
*/
public function appendRow($row): self
{
@@ -302,6 +304,9 @@ class Table
return $this;
}
+ /**
+ * @return $this
+ */
public function setRow($column, array $row)
{
$this->rows[$column] = $row;
@@ -309,6 +314,9 @@ class Table
return $this;
}
+ /**
+ * @return $this
+ */
public function setHeaderTitle(?string $title): self
{
$this->headerTitle = $title;
@@ -316,6 +324,9 @@ class Table
return $this;
}
+ /**
+ * @return $this
+ */
public function setFooterTitle(?string $title): self
{
$this->footerTitle = $title;
@@ -323,6 +334,9 @@ class Table
return $this;
}
+ /**
+ * @return $this
+ */
public function setHorizontal(bool $horizontal = true): self
{
$this->horizontal = $horizontal;
@@ -369,41 +383,59 @@ class Table
$this->calculateNumberOfColumns($rows);
- $rows = $this->buildTableRows($rows);
- $this->calculateColumnsWidth($rows);
+ $rowGroups = $this->buildTableRows($rows);
+ $this->calculateColumnsWidth($rowGroups);
$isHeader = !$this->horizontal;
$isFirstRow = $this->horizontal;
$hasTitle = (bool) $this->headerTitle;
- foreach ($rows as $row) {
- if ($divider === $row) {
- $isHeader = false;
- $isFirstRow = true;
- continue;
- }
- if ($row instanceof TableSeparator) {
- $this->renderRowSeparator();
+ foreach ($rowGroups as $rowGroup) {
+ $isHeaderSeparatorRendered = false;
- continue;
- }
- if (!$row) {
- continue;
- }
+ foreach ($rowGroup as $row) {
+ if ($divider === $row) {
+ $isHeader = false;
+ $isFirstRow = true;
- if ($isHeader || $isFirstRow) {
- $this->renderRowSeparator(
- $isHeader ? self::SEPARATOR_TOP : self::SEPARATOR_TOP_BOTTOM,
- $hasTitle ? $this->headerTitle : null,
- $hasTitle ? $this->style->getHeaderTitleFormat() : null
- );
- $isFirstRow = false;
- $hasTitle = false;
- }
- if ($this->horizontal) {
- $this->renderRow($row, $this->style->getCellRowFormat(), $this->style->getCellHeaderFormat());
- } else {
- $this->renderRow($row, $isHeader ? $this->style->getCellHeaderFormat() : $this->style->getCellRowFormat());
+ continue;
+ }
+
+ if ($row instanceof TableSeparator) {
+ $this->renderRowSeparator();
+
+ continue;
+ }
+
+ if (!$row) {
+ continue;
+ }
+
+ if ($isHeader && !$isHeaderSeparatorRendered) {
+ $this->renderRowSeparator(
+ $isHeader ? self::SEPARATOR_TOP : self::SEPARATOR_TOP_BOTTOM,
+ $hasTitle ? $this->headerTitle : null,
+ $hasTitle ? $this->style->getHeaderTitleFormat() : null
+ );
+ $hasTitle = false;
+ $isHeaderSeparatorRendered = true;
+ }
+
+ if ($isFirstRow) {
+ $this->renderRowSeparator(
+ $isHeader ? self::SEPARATOR_TOP : self::SEPARATOR_TOP_BOTTOM,
+ $hasTitle ? $this->headerTitle : null,
+ $hasTitle ? $this->style->getHeaderTitleFormat() : null
+ );
+ $isFirstRow = false;
+ $hasTitle = false;
+ }
+
+ if ($this->horizontal) {
+ $this->renderRow($row, $this->style->getCellRowFormat(), $this->style->getCellHeaderFormat());
+ } else {
+ $this->renderRow($row, $isHeader ? $this->style->getCellHeaderFormat() : $this->style->getCellRowFormat());
+ }
}
}
$this->renderRowSeparator(self::SEPARATOR_BOTTOM, $this->footerTitle, $this->style->getFooterTitleFormat());
@@ -448,11 +480,11 @@ class Table
}
if (null !== $title) {
- $titleLength = Helper::strlenWithoutDecoration($formatter = $this->output->getFormatter(), $formattedTitle = sprintf($titleFormat, $title));
- $markupLength = Helper::strlen($markup);
+ $titleLength = Helper::width(Helper::removeDecoration($formatter = $this->output->getFormatter(), $formattedTitle = sprintf($titleFormat, $title)));
+ $markupLength = Helper::width($markup);
if ($titleLength > $limit = $markupLength - 4) {
$titleLength = $limit;
- $formatLength = Helper::strlenWithoutDecoration($formatter, sprintf($titleFormat, ''));
+ $formatLength = Helper::width(Helper::removeDecoration($formatter, sprintf($titleFormat, '')));
$formattedTitle = sprintf($titleFormat, Helper::substr($title, 0, $limit - $formatLength - 3).'...');
}
@@ -525,10 +557,33 @@ class Table
return sprintf($style->getBorderFormat(), str_repeat($style->getBorderChars()[2], $width));
}
- $width += Helper::strlen($cell) - Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell);
+ $width += Helper::length($cell) - Helper::length(Helper::removeDecoration($this->output->getFormatter(), $cell));
$content = sprintf($style->getCellRowContentFormat(), $cell);
- return sprintf($cellFormat, str_pad($content, $width, $style->getPaddingChar(), $style->getPadType()));
+ $padType = $style->getPadType();
+ if ($cell instanceof TableCell && $cell->getStyle() instanceof TableCellStyle) {
+ $isNotStyledByTag = !preg_match('/^<(\w+|(\w+=[\w,]+;?)*)>.+<\/(\w+|(\w+=\w+;?)*)?>$/', $cell);
+ if ($isNotStyledByTag) {
+ $cellFormat = $cell->getStyle()->getCellFormat();
+ if (!\is_string($cellFormat)) {
+ $tag = http_build_query($cell->getStyle()->getTagOptions(), '', ';');
+ $cellFormat = '<'.$tag.'>%s>';
+ }
+
+ if (strstr($content, '>')) {
+ $content = str_replace('>', '', $content);
+ $width -= 3;
+ }
+ if (strstr($content, '')) {
+ $content = str_replace('', '', $content);
+ $width -= \strlen('');
+ }
+ }
+
+ $padType = $cell->getStyle()->getPadByAlign();
+ }
+
+ return sprintf($cellFormat, str_pad($content, $width, $style->getPaddingChar(), $padType));
}
/**
@@ -560,7 +615,7 @@ class Table
foreach ($rows[$rowKey] as $column => $cell) {
$colspan = $cell instanceof TableCell ? $cell->getColspan() : 1;
- if (isset($this->columnMaxWidths[$column]) && Helper::strlenWithoutDecoration($formatter, $cell) > $this->columnMaxWidths[$column]) {
+ if (isset($this->columnMaxWidths[$column]) && Helper::width(Helper::removeDecoration($formatter, $cell)) > $this->columnMaxWidths[$column]) {
$cell = $formatter->formatAndWrap($cell, $this->columnMaxWidths[$column] * $colspan);
}
if (!strstr($cell ?? '', "\n")) {
@@ -568,7 +623,7 @@ class Table
}
$escaped = implode("\n", array_map([OutputFormatter::class, 'escapeTrailingBackslash'], explode("\n", $cell)));
$cell = $cell instanceof TableCell ? new TableCell($escaped, ['colspan' => $cell->getColspan()]) : $escaped;
- $lines = explode("\n", str_replace("\n", "\n>", $cell));
+ $lines = explode("\n", str_replace("\n", ">\n", $cell));
foreach ($lines as $lineKey => $line) {
if ($colspan > 1) {
$line = new TableCell($line, ['colspan' => $colspan]);
@@ -587,13 +642,14 @@ class Table
return new TableRows(function () use ($rows, $unmergedRows): \Traversable {
foreach ($rows as $rowKey => $row) {
- yield $row instanceof TableSeparator ? $row : $this->fillCells($row);
+ $rowGroup = [$row instanceof TableSeparator ? $row : $this->fillCells($row)];
if (isset($unmergedRows[$rowKey])) {
foreach ($unmergedRows[$rowKey] as $row) {
- yield $row instanceof TableSeparator ? $row : $this->fillCells($row);
+ $rowGroup[] = $row instanceof TableSeparator ? $row : $this->fillCells($row);
}
}
+ yield $rowGroup;
}
});
}
@@ -622,8 +678,8 @@ class Table
{
$unmergedRows = [];
foreach ($rows[$line] as $column => $cell) {
- if (null !== $cell && !$cell instanceof TableCell && !is_scalar($cell) && !(\is_object($cell) && method_exists($cell, '__toString'))) {
- throw new InvalidArgumentException(sprintf('A cell must be a TableCell, a scalar or an object implementing "__toString()", "%s" given.', \gettype($cell)));
+ if (null !== $cell && !$cell instanceof TableCell && !\is_scalar($cell) && !(\is_object($cell) && method_exists($cell, '__toString'))) {
+ throw new InvalidArgumentException(sprintf('A cell must be a TableCell, a scalar or an object implementing "__toString()", "%s" given.', get_debug_type($cell)));
}
if ($cell instanceof TableCell && $cell->getRowspan() > 1) {
$nbLines = $cell->getRowspan() - 1;
@@ -632,7 +688,7 @@ class Table
$lines = explode("\n", str_replace("\n", "\n>", $cell));
$nbLines = \count($lines) > $nbLines ? substr_count($cell, "\n") : $nbLines;
- $rows[$line][$column] = new TableCell($lines[0], ['colspan' => $cell->getColspan()]);
+ $rows[$line][$column] = new TableCell($lines[0], ['colspan' => $cell->getColspan(), 'style' => $cell->getStyle()]);
unset($lines[0]);
}
@@ -640,7 +696,7 @@ class Table
$unmergedRows = array_replace_recursive(array_fill($line + 1, $nbLines, []), $unmergedRows);
foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) {
$value = $lines[$unmergedRowKey - $line] ?? '';
- $unmergedRows[$unmergedRowKey][$column] = new TableCell($value, ['colspan' => $cell->getColspan()]);
+ $unmergedRows[$unmergedRowKey][$column] = new TableCell($value, ['colspan' => $cell->getColspan(), 'style' => $cell->getStyle()]);
if ($nbLines === $unmergedRowKey - $line) {
break;
}
@@ -734,38 +790,40 @@ class Table
/**
* Calculates columns widths.
*/
- private function calculateColumnsWidth(iterable $rows)
+ private function calculateColumnsWidth(iterable $groups)
{
for ($column = 0; $column < $this->numberOfColumns; ++$column) {
$lengths = [];
- foreach ($rows as $row) {
- if ($row instanceof TableSeparator) {
- continue;
- }
+ foreach ($groups as $group) {
+ foreach ($group as $row) {
+ if ($row instanceof TableSeparator) {
+ continue;
+ }
- foreach ($row as $i => $cell) {
- if ($cell instanceof TableCell) {
- $textContent = Helper::removeDecoration($this->output->getFormatter(), $cell);
- $textLength = Helper::strlen($textContent);
- if ($textLength > 0) {
- $contentColumns = str_split($textContent, ceil($textLength / $cell->getColspan()));
- foreach ($contentColumns as $position => $content) {
- $row[$i + $position] = $content;
+ foreach ($row as $i => $cell) {
+ if ($cell instanceof TableCell) {
+ $textContent = Helper::removeDecoration($this->output->getFormatter(), $cell);
+ $textLength = Helper::width($textContent);
+ if ($textLength > 0) {
+ $contentColumns = mb_str_split($textContent, ceil($textLength / $cell->getColspan()));
+ foreach ($contentColumns as $position => $content) {
+ $row[$i + $position] = $content;
+ }
}
}
}
- }
- $lengths[] = $this->getCellWidth($row, $column);
+ $lengths[] = $this->getCellWidth($row, $column);
+ }
}
- $this->effectiveColumnWidths[$column] = max($lengths) + Helper::strlen($this->style->getCellRowContentFormat()) - 2;
+ $this->effectiveColumnWidths[$column] = max($lengths) + Helper::width($this->style->getCellRowContentFormat()) - 2;
}
}
private function getColumnSeparatorWidth(): int
{
- return Helper::strlen(sprintf($this->style->getBorderFormat(), $this->style->getBorderChars()[3]));
+ return Helper::width(sprintf($this->style->getBorderFormat(), $this->style->getBorderChars()[3]));
}
private function getCellWidth(array $row, int $column): int
@@ -774,7 +832,7 @@ class Table
if (isset($row[$column])) {
$cell = $row[$column];
- $cellWidth = Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell);
+ $cellWidth = Helper::width(Helper::removeDecoration($this->output->getFormatter(), $cell));
}
$columnWidth = $this->columnWidths[$column] ?? 0;
@@ -792,6 +850,9 @@ class Table
$this->numberOfColumns = null;
}
+ /**
+ * @return array
+ */
private static function initStyles(): array
{
$borderless = new TableStyle();
@@ -804,9 +865,9 @@ class Table
$compact = new TableStyle();
$compact
->setHorizontalBorderChars('')
- ->setVerticalBorderChars(' ')
+ ->setVerticalBorderChars('')
->setDefaultCrossingChar('')
- ->setCellRowContentFormat('%s')
+ ->setCellRowContentFormat('%s ')
;
$styleGuide = new TableStyle();
diff --git a/vendor/symfony/console/Helper/TableCell.php b/vendor/symfony/console/Helper/TableCell.php
index 5b6af4a93..1a7bc6ede 100644
--- a/vendor/symfony/console/Helper/TableCell.php
+++ b/vendor/symfony/console/Helper/TableCell.php
@@ -22,6 +22,7 @@ class TableCell
private $options = [
'rowspan' => 1,
'colspan' => 1,
+ 'style' => null,
];
public function __construct(string $value = '', array $options = [])
@@ -33,6 +34,10 @@ class TableCell
throw new InvalidArgumentException(sprintf('The TableCell does not support the following options: \'%s\'.', implode('\', \'', $diff)));
}
+ if (isset($options['style']) && !$options['style'] instanceof TableCellStyle) {
+ throw new InvalidArgumentException('The style option must be an instance of "TableCellStyle".');
+ }
+
$this->options = array_merge($this->options, $options);
}
@@ -65,4 +70,9 @@ class TableCell
{
return (int) $this->options['rowspan'];
}
+
+ public function getStyle(): ?TableCellStyle
+ {
+ return $this->options['style'];
+ }
}
diff --git a/vendor/symfony/console/Helper/TableCellStyle.php b/vendor/symfony/console/Helper/TableCellStyle.php
new file mode 100644
index 000000000..19cd0ffc6
--- /dev/null
+++ b/vendor/symfony/console/Helper/TableCellStyle.php
@@ -0,0 +1,89 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Console\Helper;
+
+use Symfony\Component\Console\Exception\InvalidArgumentException;
+
+/**
+ * @author Yewhen Khoptynskyi
+ */
+class TableCellStyle
+{
+ public const DEFAULT_ALIGN = 'left';
+
+ private const TAG_OPTIONS = [
+ 'fg',
+ 'bg',
+ 'options',
+ ];
+
+ private const ALIGN_MAP = [
+ 'left' => \STR_PAD_RIGHT,
+ 'center' => \STR_PAD_BOTH,
+ 'right' => \STR_PAD_LEFT,
+ ];
+
+ private $options = [
+ 'fg' => 'default',
+ 'bg' => 'default',
+ 'options' => null,
+ 'align' => self::DEFAULT_ALIGN,
+ 'cellFormat' => null,
+ ];
+
+ public function __construct(array $options = [])
+ {
+ if ($diff = array_diff(array_keys($options), array_keys($this->options))) {
+ throw new InvalidArgumentException(sprintf('The TableCellStyle does not support the following options: \'%s\'.', implode('\', \'', $diff)));
+ }
+
+ if (isset($options['align']) && !\array_key_exists($options['align'], self::ALIGN_MAP)) {
+ throw new InvalidArgumentException(sprintf('Wrong align value. Value must be following: \'%s\'.', implode('\', \'', array_keys(self::ALIGN_MAP))));
+ }
+
+ $this->options = array_merge($this->options, $options);
+ }
+
+ public function getOptions(): array
+ {
+ return $this->options;
+ }
+
+ /**
+ * Gets options we need for tag for example fg, bg.
+ *
+ * @return string[]
+ */
+ public function getTagOptions()
+ {
+ return array_filter(
+ $this->getOptions(),
+ function ($key) {
+ return \in_array($key, self::TAG_OPTIONS) && isset($this->options[$key]);
+ },
+ \ARRAY_FILTER_USE_KEY
+ );
+ }
+
+ /**
+ * @return int
+ */
+ public function getPadByAlign()
+ {
+ return self::ALIGN_MAP[$this->getOptions()['align']];
+ }
+
+ public function getCellFormat(): ?string
+ {
+ return $this->getOptions()['cellFormat'];
+ }
+}
diff --git a/vendor/symfony/console/Helper/TableRows.php b/vendor/symfony/console/Helper/TableRows.php
index 16aabb3fc..cbc07d294 100644
--- a/vendor/symfony/console/Helper/TableRows.php
+++ b/vendor/symfony/console/Helper/TableRows.php
@@ -18,15 +18,13 @@ class TableRows implements \IteratorAggregate
{
private $generator;
- public function __construct(callable $generator)
+ public function __construct(\Closure $generator)
{
$this->generator = $generator;
}
public function getIterator(): \Traversable
{
- $g = $this->generator;
-
- return $g();
+ return ($this->generator)();
}
}
diff --git a/vendor/symfony/console/Helper/TableStyle.php b/vendor/symfony/console/Helper/TableStyle.php
index a8df59b3a..dfc41e6a4 100644
--- a/vendor/symfony/console/Helper/TableStyle.php
+++ b/vendor/symfony/console/Helper/TableStyle.php
@@ -51,11 +51,9 @@ class TableStyle
/**
* Sets padding character, used for cell padding.
*
- * @param string $paddingChar
- *
* @return $this
*/
- public function setPaddingChar($paddingChar)
+ public function setPaddingChar(string $paddingChar)
{
if (!$paddingChar) {
throw new LogicException('The padding char must not be empty.');
@@ -90,8 +88,7 @@ class TableStyle
* ╚═══════════════╧══════════════════════════╧══════════════════╝
*
*
- * @param string $outside Outside border char (see #1 of example)
- * @param string|null $inside Inside border char (see #2 of example), equals $outside if null
+ * @return $this
*/
public function setHorizontalBorderChars(string $outside, string $inside = null): self
{
@@ -101,36 +98,6 @@ class TableStyle
return $this;
}
- /**
- * Sets horizontal border character.
- *
- * @param string $horizontalBorderChar
- *
- * @return $this
- *
- * @deprecated since Symfony 4.1, use {@link setHorizontalBorderChars()} instead.
- */
- public function setHorizontalBorderChar($horizontalBorderChar)
- {
- @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use setHorizontalBorderChars() instead.', __METHOD__), \E_USER_DEPRECATED);
-
- return $this->setHorizontalBorderChars($horizontalBorderChar, $horizontalBorderChar);
- }
-
- /**
- * Gets horizontal border character.
- *
- * @return string
- *
- * @deprecated since Symfony 4.1, use {@link getBorderChars()} instead.
- */
- public function getHorizontalBorderChar()
- {
- @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use getBorderChars() instead.', __METHOD__), \E_USER_DEPRECATED);
-
- return $this->horizontalOutsideBorderChar;
- }
-
/**
* Sets vertical border characters.
*
@@ -146,8 +113,7 @@ class TableStyle
* ╚═══════════════╧══════════════════════════╧══════════════════╝
*
*
- * @param string $outside Outside border char (see #1 of example)
- * @param string|null $inside Inside border char (see #2 of example), equals $outside if null
+ * @return $this
*/
public function setVerticalBorderChars(string $outside, string $inside = null): self
{
@@ -157,36 +123,6 @@ class TableStyle
return $this;
}
- /**
- * Sets vertical border character.
- *
- * @param string $verticalBorderChar
- *
- * @return $this
- *
- * @deprecated since Symfony 4.1, use {@link setVerticalBorderChars()} instead.
- */
- public function setVerticalBorderChar($verticalBorderChar)
- {
- @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use setVerticalBorderChars() instead.', __METHOD__), \E_USER_DEPRECATED);
-
- return $this->setVerticalBorderChars($verticalBorderChar, $verticalBorderChar);
- }
-
- /**
- * Gets vertical border character.
- *
- * @return string
- *
- * @deprecated since Symfony 4.1, use {@link getBorderChars()} instead.
- */
- public function getVerticalBorderChar()
- {
- @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use getBorderChars() instead.', __METHOD__), \E_USER_DEPRECATED);
-
- return $this->verticalOutsideBorderChar;
- }
-
/**
* Gets border characters.
*
@@ -230,6 +166,8 @@ class TableStyle
* @param string|null $topLeftBottom Top left bottom char (see #8' of example), equals to $midLeft if null
* @param string|null $topMidBottom Top mid bottom char (see #0' of example), equals to $cross if null
* @param string|null $topRightBottom Top right bottom char (see #4' of example), equals to $midRight if null
+ *
+ * @return $this
*/
public function setCrossingChars(string $cross, string $topLeft, string $topMid, string $topRight, string $midRight, string $bottomRight, string $bottomMid, string $bottomLeft, string $midLeft, string $topLeftBottom = null, string $topMidBottom = null, string $topRightBottom = null): self
{
@@ -259,22 +197,6 @@ class TableStyle
return $this->setCrossingChars($char, $char, $char, $char, $char, $char, $char, $char, $char);
}
- /**
- * Sets crossing character.
- *
- * @param string $crossingChar
- *
- * @return $this
- *
- * @deprecated since Symfony 4.1. Use {@link setDefaultCrossingChar()} instead.
- */
- public function setCrossingChar($crossingChar)
- {
- @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1. Use setDefaultCrossingChar() instead.', __METHOD__), \E_USER_DEPRECATED);
-
- return $this->setDefaultCrossingChar($crossingChar);
- }
-
/**
* Gets crossing character.
*
@@ -311,11 +233,9 @@ class TableStyle
/**
* Sets header cell format.
*
- * @param string $cellHeaderFormat
- *
* @return $this
*/
- public function setCellHeaderFormat($cellHeaderFormat)
+ public function setCellHeaderFormat(string $cellHeaderFormat)
{
$this->cellHeaderFormat = $cellHeaderFormat;
@@ -335,11 +255,9 @@ class TableStyle
/**
* Sets row cell format.
*
- * @param string $cellRowFormat
- *
* @return $this
*/
- public function setCellRowFormat($cellRowFormat)
+ public function setCellRowFormat(string $cellRowFormat)
{
$this->cellRowFormat = $cellRowFormat;
@@ -359,11 +277,9 @@ class TableStyle
/**
* Sets row cell content format.
*
- * @param string $cellRowContentFormat
- *
* @return $this
*/
- public function setCellRowContentFormat($cellRowContentFormat)
+ public function setCellRowContentFormat(string $cellRowContentFormat)
{
$this->cellRowContentFormat = $cellRowContentFormat;
@@ -383,11 +299,9 @@ class TableStyle
/**
* Sets table border format.
*
- * @param string $borderFormat
- *
* @return $this
*/
- public function setBorderFormat($borderFormat)
+ public function setBorderFormat(string $borderFormat)
{
$this->borderFormat = $borderFormat;
@@ -407,11 +321,9 @@ class TableStyle
/**
* Sets cell padding type.
*
- * @param int $padType STR_PAD_*
- *
* @return $this
*/
- public function setPadType($padType)
+ public function setPadType(int $padType)
{
if (!\in_array($padType, [\STR_PAD_LEFT, \STR_PAD_RIGHT, \STR_PAD_BOTH], true)) {
throw new InvalidArgumentException('Invalid padding type. Expected one of (STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH).');
@@ -437,6 +349,9 @@ class TableStyle
return $this->headerTitleFormat;
}
+ /**
+ * @return $this
+ */
public function setHeaderTitleFormat(string $format): self
{
$this->headerTitleFormat = $format;
@@ -449,6 +364,9 @@ class TableStyle
return $this->footerTitleFormat;
}
+ /**
+ * @return $this
+ */
public function setFooterTitleFormat(string $format): self
{
$this->footerTitleFormat = $format;
diff --git a/vendor/symfony/console/Input/ArgvInput.php b/vendor/symfony/console/Input/ArgvInput.php
index 63f40f271..675b9ef58 100644
--- a/vendor/symfony/console/Input/ArgvInput.php
+++ b/vendor/symfony/console/Input/ArgvInput.php
@@ -43,9 +43,6 @@ class ArgvInput extends Input
private $tokens;
private $parsed;
- /**
- * @param array|null $argv An array of parameters from the CLI (in the argv format)
- */
public function __construct(array $argv = null, InputDefinition $definition = null)
{
$argv = $argv ?? $_SERVER['argv'] ?? [];
@@ -71,20 +68,27 @@ class ArgvInput extends Input
$parseOptions = true;
$this->parsed = $this->tokens;
while (null !== $token = array_shift($this->parsed)) {
- if ($parseOptions && '' == $token) {
- $this->parseArgument($token);
- } elseif ($parseOptions && '--' == $token) {
- $parseOptions = false;
- } elseif ($parseOptions && str_starts_with($token, '--')) {
- $this->parseLongOption($token);
- } elseif ($parseOptions && '-' === $token[0] && '-' !== $token) {
- $this->parseShortOption($token);
- } else {
- $this->parseArgument($token);
- }
+ $parseOptions = $this->parseToken($token, $parseOptions);
}
}
+ protected function parseToken(string $token, bool $parseOptions): bool
+ {
+ if ($parseOptions && '' == $token) {
+ $this->parseArgument($token);
+ } elseif ($parseOptions && '--' == $token) {
+ return false;
+ } elseif ($parseOptions && str_starts_with($token, '--')) {
+ $this->parseLongOption($token);
+ } elseif ($parseOptions && '-' === $token[0] && '-' !== $token) {
+ $this->parseShortOption($token);
+ } else {
+ $this->parseArgument($token);
+ }
+
+ return $parseOptions;
+ }
+
/**
* Parses a short option.
*/
@@ -168,11 +172,25 @@ class ArgvInput extends Input
// unexpected argument
} else {
$all = $this->definition->getArguments();
- if (\count($all)) {
- throw new RuntimeException(sprintf('Too many arguments, expected arguments "%s".', implode('" "', array_keys($all))));
+ $symfonyCommandName = null;
+ if (($inputArgument = $all[$key = array_key_first($all)] ?? null) && 'command' === $inputArgument->getName()) {
+ $symfonyCommandName = $this->arguments['command'] ?? null;
+ unset($all[$key]);
}
- throw new RuntimeException(sprintf('No arguments expected, got "%s".', $token));
+ if (\count($all)) {
+ if ($symfonyCommandName) {
+ $message = sprintf('Too many arguments to "%s" command, expected arguments "%s".', $symfonyCommandName, implode('" "', array_keys($all)));
+ } else {
+ $message = sprintf('Too many arguments, expected arguments "%s".', implode('" "', array_keys($all)));
+ }
+ } elseif ($symfonyCommandName) {
+ $message = sprintf('No arguments expected for "%s" command, got "%s".', $symfonyCommandName, $token);
+ } else {
+ $message = sprintf('No arguments expected, got "%s".', $token);
+ }
+
+ throw new RuntimeException($message);
}
}
@@ -198,7 +216,17 @@ class ArgvInput extends Input
private function addLongOption(string $name, $value)
{
if (!$this->definition->hasOption($name)) {
- throw new RuntimeException(sprintf('The "--%s" option does not exist.', $name));
+ if (!$this->definition->hasNegation($name)) {
+ throw new RuntimeException(sprintf('The "--%s" option does not exist.', $name));
+ }
+
+ $optionName = $this->definition->negationToName($name);
+ if (null !== $value) {
+ throw new RuntimeException(sprintf('The "--%s" option does not accept a value.', $name));
+ }
+ $this->options[$optionName] = false;
+
+ return;
}
$option = $this->definition->getOption($name);
@@ -273,7 +301,7 @@ class ArgvInput extends Input
/**
* {@inheritdoc}
*/
- public function hasParameterOption($values, $onlyParams = false)
+ public function hasParameterOption($values, bool $onlyParams = false)
{
$values = (array) $values;
@@ -298,7 +326,7 @@ class ArgvInput extends Input
/**
* {@inheritdoc}
*/
- public function getParameterOption($values, $default = false, $onlyParams = false)
+ public function getParameterOption($values, $default = false, bool $onlyParams = false)
{
$values = (array) $values;
$tokens = $this->tokens;
diff --git a/vendor/symfony/console/Input/ArrayInput.php b/vendor/symfony/console/Input/ArrayInput.php
index 30bd2054a..c65161484 100644
--- a/vendor/symfony/console/Input/ArrayInput.php
+++ b/vendor/symfony/console/Input/ArrayInput.php
@@ -53,7 +53,7 @@ class ArrayInput extends Input
/**
* {@inheritdoc}
*/
- public function hasParameterOption($values, $onlyParams = false)
+ public function hasParameterOption($values, bool $onlyParams = false)
{
$values = (array) $values;
@@ -77,7 +77,7 @@ class ArrayInput extends Input
/**
* {@inheritdoc}
*/
- public function getParameterOption($values, $default = false, $onlyParams = false)
+ public function getParameterOption($values, $default = false, bool $onlyParams = false)
{
$values = (array) $values;
@@ -166,7 +166,14 @@ class ArrayInput extends Input
private function addLongOption(string $name, $value)
{
if (!$this->definition->hasOption($name)) {
- throw new InvalidOptionException(sprintf('The "--%s" option does not exist.', $name));
+ if (!$this->definition->hasNegation($name)) {
+ throw new InvalidOptionException(sprintf('The "--%s" option does not exist.', $name));
+ }
+
+ $optionName = $this->definition->negationToName($name);
+ $this->options[$optionName] = false;
+
+ return;
}
$option = $this->definition->getOption($name);
diff --git a/vendor/symfony/console/Input/Input.php b/vendor/symfony/console/Input/Input.php
index d7f29073e..d37460ed3 100644
--- a/vendor/symfony/console/Input/Input.php
+++ b/vendor/symfony/console/Input/Input.php
@@ -88,9 +88,9 @@ abstract class Input implements InputInterface, StreamableInputInterface
/**
* {@inheritdoc}
*/
- public function setInteractive($interactive)
+ public function setInteractive(bool $interactive)
{
- $this->interactive = (bool) $interactive;
+ $this->interactive = $interactive;
}
/**
@@ -104,9 +104,9 @@ abstract class Input implements InputInterface, StreamableInputInterface
/**
* {@inheritdoc}
*/
- public function getArgument($name)
+ public function getArgument(string $name)
{
- if (!$this->definition->hasArgument((string) $name)) {
+ if (!$this->definition->hasArgument($name)) {
throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
}
@@ -116,9 +116,9 @@ abstract class Input implements InputInterface, StreamableInputInterface
/**
* {@inheritdoc}
*/
- public function setArgument($name, $value)
+ public function setArgument(string $name, $value)
{
- if (!$this->definition->hasArgument((string) $name)) {
+ if (!$this->definition->hasArgument($name)) {
throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name));
}
@@ -128,9 +128,9 @@ abstract class Input implements InputInterface, StreamableInputInterface
/**
* {@inheritdoc}
*/
- public function hasArgument($name)
+ public function hasArgument(string $name)
{
- return $this->definition->hasArgument((string) $name);
+ return $this->definition->hasArgument($name);
}
/**
@@ -144,8 +144,16 @@ abstract class Input implements InputInterface, StreamableInputInterface
/**
* {@inheritdoc}
*/
- public function getOption($name)
+ public function getOption(string $name)
{
+ if ($this->definition->hasNegation($name)) {
+ if (null === $value = $this->getOption($this->definition->negationToName($name))) {
+ return $value;
+ }
+
+ return !$value;
+ }
+
if (!$this->definition->hasOption($name)) {
throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
}
@@ -156,9 +164,13 @@ abstract class Input implements InputInterface, StreamableInputInterface
/**
* {@inheritdoc}
*/
- public function setOption($name, $value)
+ public function setOption(string $name, $value)
{
- if (!$this->definition->hasOption($name)) {
+ if ($this->definition->hasNegation($name)) {
+ $this->options[$this->definition->negationToName($name)] = !$value;
+
+ return;
+ } elseif (!$this->definition->hasOption($name)) {
throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name));
}
@@ -168,19 +180,17 @@ abstract class Input implements InputInterface, StreamableInputInterface
/**
* {@inheritdoc}
*/
- public function hasOption($name)
+ public function hasOption(string $name)
{
- return $this->definition->hasOption($name);
+ return $this->definition->hasOption($name) || $this->definition->hasNegation($name);
}
/**
* Escapes a token through escapeshellarg if it contains unsafe chars.
*
- * @param string $token
- *
* @return string
*/
- public function escapeToken($token)
+ public function escapeToken(string $token)
{
return preg_match('{^[\w-]+$}', $token) ? $token : escapeshellarg($token);
}
diff --git a/vendor/symfony/console/Input/InputArgument.php b/vendor/symfony/console/Input/InputArgument.php
index 085aca5a7..8a64f7ac8 100644
--- a/vendor/symfony/console/Input/InputArgument.php
+++ b/vendor/symfony/console/Input/InputArgument.php
@@ -32,7 +32,7 @@ class InputArgument
/**
* @param string $name The argument name
- * @param int|null $mode The argument mode: self::REQUIRED or self::OPTIONAL
+ * @param int|null $mode The argument mode: a bit mask of self::REQUIRED, self::OPTIONAL and self::IS_ARRAY
* @param string $description A description text
* @param string|bool|int|float|array|null $default The default value (for self::OPTIONAL mode only)
*
@@ -56,7 +56,7 @@ class InputArgument
/**
* Returns the argument name.
*
- * @return string The argument name
+ * @return string
*/
public function getName()
{
@@ -92,7 +92,7 @@ class InputArgument
*/
public function setDefault($default = null)
{
- if (self::REQUIRED === $this->mode && null !== $default) {
+ if ($this->isRequired() && null !== $default) {
throw new LogicException('Cannot set a default value except for InputArgument::OPTIONAL mode.');
}
@@ -120,7 +120,7 @@ class InputArgument
/**
* Returns the description text.
*
- * @return string The description text
+ * @return string
*/
public function getDescription()
{
diff --git a/vendor/symfony/console/Input/InputDefinition.php b/vendor/symfony/console/Input/InputDefinition.php
index e2cd6d714..11f704f0e 100644
--- a/vendor/symfony/console/Input/InputDefinition.php
+++ b/vendor/symfony/console/Input/InputDefinition.php
@@ -30,9 +30,10 @@ class InputDefinition
{
private $arguments;
private $requiredCount;
- private $hasAnArrayArgument = false;
- private $hasOptional;
+ private $lastArrayArgument;
+ private $lastOptionalArgument;
private $options;
+ private $negations;
private $shortcuts;
/**
@@ -67,12 +68,12 @@ class InputDefinition
*
* @param InputArgument[] $arguments An array of InputArgument objects
*/
- public function setArguments($arguments = [])
+ public function setArguments(array $arguments = [])
{
$this->arguments = [];
$this->requiredCount = 0;
- $this->hasOptional = false;
- $this->hasAnArrayArgument = false;
+ $this->lastOptionalArgument = null;
+ $this->lastArrayArgument = null;
$this->addArguments($arguments);
}
@@ -81,7 +82,7 @@ class InputDefinition
*
* @param InputArgument[] $arguments An array of InputArgument objects
*/
- public function addArguments($arguments = [])
+ public function addArguments(?array $arguments = [])
{
if (null !== $arguments) {
foreach ($arguments as $argument) {
@@ -99,22 +100,22 @@ class InputDefinition
throw new LogicException(sprintf('An argument with name "%s" already exists.', $argument->getName()));
}
- if ($this->hasAnArrayArgument) {
- throw new LogicException('Cannot add an argument after an array argument.');
+ if (null !== $this->lastArrayArgument) {
+ throw new LogicException(sprintf('Cannot add a required argument "%s" after an array argument "%s".', $argument->getName(), $this->lastArrayArgument->getName()));
}
- if ($argument->isRequired() && $this->hasOptional) {
- throw new LogicException('Cannot add a required argument after an optional one.');
+ if ($argument->isRequired() && null !== $this->lastOptionalArgument) {
+ throw new LogicException(sprintf('Cannot add a required argument "%s" after an optional one "%s".', $argument->getName(), $this->lastOptionalArgument->getName()));
}
if ($argument->isArray()) {
- $this->hasAnArrayArgument = true;
+ $this->lastArrayArgument = $argument;
}
if ($argument->isRequired()) {
++$this->requiredCount;
} else {
- $this->hasOptional = true;
+ $this->lastOptionalArgument = $argument;
}
$this->arguments[$argument->getName()] = $argument;
@@ -125,7 +126,7 @@ class InputDefinition
*
* @param string|int $name The InputArgument name or position
*
- * @return InputArgument An InputArgument object
+ * @return InputArgument
*
* @throws InvalidArgumentException When argument given doesn't exist
*/
@@ -145,7 +146,7 @@ class InputDefinition
*
* @param string|int $name The InputArgument name or position
*
- * @return bool true if the InputArgument object exists, false otherwise
+ * @return bool
*/
public function hasArgument($name)
{
@@ -157,7 +158,7 @@ class InputDefinition
/**
* Gets the array of InputArgument objects.
*
- * @return InputArgument[] An array of InputArgument objects
+ * @return InputArgument[]
*/
public function getArguments()
{
@@ -167,17 +168,17 @@ class InputDefinition
/**
* Returns the number of InputArguments.
*
- * @return int The number of InputArguments
+ * @return int
*/
public function getArgumentCount()
{
- return $this->hasAnArrayArgument ? \PHP_INT_MAX : \count($this->arguments);
+ return null !== $this->lastArrayArgument ? \PHP_INT_MAX : \count($this->arguments);
}
/**
* Returns the number of required InputArguments.
*
- * @return int The number of required InputArguments
+ * @return int
*/
public function getArgumentRequiredCount()
{
@@ -202,10 +203,11 @@ class InputDefinition
*
* @param InputOption[] $options An array of InputOption objects
*/
- public function setOptions($options = [])
+ public function setOptions(array $options = [])
{
$this->options = [];
$this->shortcuts = [];
+ $this->negations = [];
$this->addOptions($options);
}
@@ -214,7 +216,7 @@ class InputDefinition
*
* @param InputOption[] $options An array of InputOption objects
*/
- public function addOptions($options = [])
+ public function addOptions(array $options = [])
{
foreach ($options as $option) {
$this->addOption($option);
@@ -229,6 +231,9 @@ class InputDefinition
if (isset($this->options[$option->getName()]) && !$option->equals($this->options[$option->getName()])) {
throw new LogicException(sprintf('An option named "%s" already exists.', $option->getName()));
}
+ if (isset($this->negations[$option->getName()])) {
+ throw new LogicException(sprintf('An option named "%s" already exists.', $option->getName()));
+ }
if ($option->getShortcut()) {
foreach (explode('|', $option->getShortcut()) as $shortcut) {
@@ -244,18 +249,24 @@ class InputDefinition
$this->shortcuts[$shortcut] = $option->getName();
}
}
+
+ if ($option->isNegatable()) {
+ $negatedName = 'no-'.$option->getName();
+ if (isset($this->options[$negatedName])) {
+ throw new LogicException(sprintf('An option named "%s" already exists.', $negatedName));
+ }
+ $this->negations[$negatedName] = $option->getName();
+ }
}
/**
* Returns an InputOption by name.
*
- * @param string $name The InputOption name
- *
- * @return InputOption A InputOption object
+ * @return InputOption
*
* @throws InvalidArgumentException When option given doesn't exist
*/
- public function getOption($name)
+ public function getOption(string $name)
{
if (!$this->hasOption($name)) {
throw new InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name));
@@ -270,11 +281,9 @@ class InputDefinition
* This method can't be used to check if the user included the option when
* executing the command (use getOption() instead).
*
- * @param string $name The InputOption name
- *
- * @return bool true if the InputOption object exists, false otherwise
+ * @return bool
*/
- public function hasOption($name)
+ public function hasOption(string $name)
{
return isset($this->options[$name]);
}
@@ -282,7 +291,7 @@ class InputDefinition
/**
* Gets the array of InputOption objects.
*
- * @return InputOption[] An array of InputOption objects
+ * @return InputOption[]
*/
public function getOptions()
{
@@ -292,23 +301,27 @@ class InputDefinition
/**
* Returns true if an InputOption object exists by shortcut.
*
- * @param string $name The InputOption shortcut
- *
- * @return bool true if the InputOption object exists, false otherwise
+ * @return bool
*/
- public function hasShortcut($name)
+ public function hasShortcut(string $name)
{
return isset($this->shortcuts[$name]);
}
+ /**
+ * Returns true if an InputOption object exists by negated name.
+ */
+ public function hasNegation(string $name): bool
+ {
+ return isset($this->negations[$name]);
+ }
+
/**
* Gets an InputOption by shortcut.
*
- * @param string $shortcut The Shortcut name
- *
- * @return InputOption An InputOption object
+ * @return InputOption
*/
- public function getOptionForShortcut($shortcut)
+ public function getOptionForShortcut(string $shortcut)
{
return $this->getOption($this->shortcutToName($shortcut));
}
@@ -342,14 +355,28 @@ class InputDefinition
return $this->shortcuts[$shortcut];
}
+ /**
+ * Returns the InputOption name given a negation.
+ *
+ * @throws InvalidArgumentException When option given does not exist
+ *
+ * @internal
+ */
+ public function negationToName(string $negation): string
+ {
+ if (!isset($this->negations[$negation])) {
+ throw new InvalidArgumentException(sprintf('The "--%s" option does not exist.', $negation));
+ }
+
+ return $this->negations[$negation];
+ }
+
/**
* Gets the synopsis.
*
- * @param bool $short Whether to return the short version (with options folded) or not
- *
- * @return string The synopsis
+ * @return string
*/
- public function getSynopsis($short = false)
+ public function getSynopsis(bool $short = false)
{
$elements = [];
@@ -368,7 +395,8 @@ class InputDefinition
}
$shortcut = $option->getShortcut() ? sprintf('-%s|', $option->getShortcut()) : '';
- $elements[] = sprintf('[%s--%s%s]', $shortcut, $option->getName(), $value);
+ $negation = $option->isNegatable() ? sprintf('|--no-%s', $option->getName()) : '';
+ $elements[] = sprintf('[%s--%s%s%s]', $shortcut, $option->getName(), $value, $negation);
}
}
diff --git a/vendor/symfony/console/Input/InputInterface.php b/vendor/symfony/console/Input/InputInterface.php
index 8efc62326..628b6037a 100644
--- a/vendor/symfony/console/Input/InputInterface.php
+++ b/vendor/symfony/console/Input/InputInterface.php
@@ -24,7 +24,7 @@ interface InputInterface
/**
* Returns the first argument from the raw parameters (not parsed).
*
- * @return string|null The value of the first argument or null otherwise
+ * @return string|null
*/
public function getFirstArgument();
@@ -39,9 +39,9 @@ interface InputInterface
* @param string|array $values The values to look for in the raw parameters (can be an array)
* @param bool $onlyParams Only check real parameters, skip those following an end of options (--) signal
*
- * @return bool true if the value is contained in the raw parameters
+ * @return bool
*/
- public function hasParameterOption($values, $onlyParams = false);
+ public function hasParameterOption($values, bool $onlyParams = false);
/**
* Returns the value of a raw option (not parsed).
@@ -55,9 +55,9 @@ interface InputInterface
* @param string|bool|int|float|array|null $default The default value to return if no result is found
* @param bool $onlyParams Only check real parameters, skip those following an end of options (--) signal
*
- * @return mixed The option value
+ * @return mixed
*/
- public function getParameterOption($values, $default = false, $onlyParams = false);
+ public function getParameterOption($values, $default = false, bool $onlyParams = false);
/**
* Binds the current Input instance with the given arguments and options.
@@ -83,32 +83,27 @@ interface InputInterface
/**
* Returns the argument value for a given argument name.
*
- * @param string $name The argument name
- *
* @return mixed
*
* @throws InvalidArgumentException When argument given doesn't exist
*/
- public function getArgument($name);
+ public function getArgument(string $name);
/**
* Sets an argument value by name.
*
- * @param string $name The argument name
- * @param mixed $value The argument value
+ * @param mixed $value The argument value
*
* @throws InvalidArgumentException When argument given doesn't exist
*/
- public function setArgument($name, $value);
+ public function setArgument(string $name, $value);
/**
* Returns true if an InputArgument object exists by name or position.
*
- * @param string $name The argument name
- *
- * @return bool true if the InputArgument object exists, false otherwise
+ * @return bool
*/
- public function hasArgument($name);
+ public function hasArgument(string $name);
/**
* Returns all the given options merged with the default values.
@@ -120,32 +115,27 @@ interface InputInterface
/**
* Returns the option value for a given option name.
*
- * @param string $name The option name
- *
* @return mixed
*
* @throws InvalidArgumentException When option given doesn't exist
*/
- public function getOption($name);
+ public function getOption(string $name);
/**
* Sets an option value by name.
*
- * @param string $name The option name
- * @param mixed $value The option value
+ * @param mixed $value The option value
*
* @throws InvalidArgumentException When option given doesn't exist
*/
- public function setOption($name, $value);
+ public function setOption(string $name, $value);
/**
* Returns true if an InputOption object exists by name.
*
- * @param string $name The InputOption name
- *
- * @return bool true if the InputOption object exists, false otherwise
+ * @return bool
*/
- public function hasOption($name);
+ public function hasOption(string $name);
/**
* Is this input means interactive?
@@ -156,8 +146,6 @@ interface InputInterface
/**
* Sets the input interactivity.
- *
- * @param bool $interactive If the input should be interactive
*/
- public function setInteractive($interactive);
+ public function setInteractive(bool $interactive);
}
diff --git a/vendor/symfony/console/Input/InputOption.php b/vendor/symfony/console/Input/InputOption.php
index c7729db20..2bec34fe1 100644
--- a/vendor/symfony/console/Input/InputOption.php
+++ b/vendor/symfony/console/Input/InputOption.php
@@ -41,6 +41,11 @@ class InputOption
*/
public const VALUE_IS_ARRAY = 8;
+ /**
+ * The option may have either positive or negative value (e.g. --ansi or --no-ansi).
+ */
+ public const VALUE_NEGATABLE = 16;
+
private $name;
private $shortcut;
private $mode;
@@ -48,11 +53,9 @@ class InputOption
private $description;
/**
- * @param string $name The option name
- * @param string|array|null $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts
- * @param int|null $mode The option mode: One of the VALUE_* constants
- * @param string $description A description text
- * @param string|bool|int|float|array|null $default The default value (must be null for self::VALUE_NONE)
+ * @param string|array|null $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts
+ * @param int|null $mode The option mode: One of the VALUE_* constants
+ * @param string|bool|int|float|array|null $default The default value (must be null for self::VALUE_NONE)
*
* @throws InvalidArgumentException If option mode is invalid or incompatible
*/
@@ -85,7 +88,7 @@ class InputOption
if (null === $mode) {
$mode = self::VALUE_NONE;
- } elseif ($mode > 15 || $mode < 1) {
+ } elseif ($mode >= (self::VALUE_NEGATABLE << 1) || $mode < 1) {
throw new InvalidArgumentException(sprintf('Option mode "%s" is not valid.', $mode));
}
@@ -97,6 +100,9 @@ class InputOption
if ($this->isArray() && !$this->acceptValue()) {
throw new InvalidArgumentException('Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value.');
}
+ if ($this->isNegatable() && $this->acceptValue()) {
+ throw new InvalidArgumentException('Impossible to have an option mode VALUE_NEGATABLE if the option also accepts a value.');
+ }
$this->setDefault($default);
}
@@ -104,7 +110,7 @@ class InputOption
/**
* Returns the option shortcut.
*
- * @return string|null The shortcut
+ * @return string|null
*/
public function getShortcut()
{
@@ -114,7 +120,7 @@ class InputOption
/**
* Returns the option name.
*
- * @return string The name
+ * @return string
*/
public function getName()
{
@@ -161,6 +167,11 @@ class InputOption
return self::VALUE_IS_ARRAY === (self::VALUE_IS_ARRAY & $this->mode);
}
+ public function isNegatable(): bool
+ {
+ return self::VALUE_NEGATABLE === (self::VALUE_NEGATABLE & $this->mode);
+ }
+
/**
* @param string|bool|int|float|array|null $default
*/
@@ -178,7 +189,7 @@ class InputOption
}
}
- $this->default = $this->acceptValue() ? $default : false;
+ $this->default = $this->acceptValue() || $this->isNegatable() ? $default : false;
}
/**
@@ -194,7 +205,7 @@ class InputOption
/**
* Returns the description text.
*
- * @return string The description text
+ * @return string
*/
public function getDescription()
{
@@ -211,6 +222,7 @@ class InputOption
return $option->getName() === $this->getName()
&& $option->getShortcut() === $this->getShortcut()
&& $option->getDefault() === $this->getDefault()
+ && $option->isNegatable() === $this->isNegatable()
&& $option->isArray() === $this->isArray()
&& $option->isValueRequired() === $this->isValueRequired()
&& $option->isValueOptional() === $this->isValueOptional()
diff --git a/vendor/symfony/console/Input/StringInput.php b/vendor/symfony/console/Input/StringInput.php
index 76f1d5030..56bb66cbf 100644
--- a/vendor/symfony/console/Input/StringInput.php
+++ b/vendor/symfony/console/Input/StringInput.php
@@ -24,7 +24,8 @@ use Symfony\Component\Console\Exception\InvalidArgumentException;
*/
class StringInput extends ArgvInput
{
- public const REGEX_STRING = '([^\s\\\\]+?)';
+ public const REGEX_STRING = '([^\s]+?)(?:\s|(? $val) {
- if (null === $val || is_scalar($val) || (\is_object($val) && method_exists($val, '__toString'))) {
+ if (null === $val || \is_scalar($val) || (\is_object($val) && method_exists($val, '__toString'))) {
$replacements["{{$key}}"] = $val;
} elseif ($val instanceof \DateTimeInterface) {
$replacements["{{$key}}"] = $val->format(\DateTime::RFC3339);
diff --git a/vendor/symfony/console/Output/BufferedOutput.php b/vendor/symfony/console/Output/BufferedOutput.php
index fefaac271..d37c6e323 100644
--- a/vendor/symfony/console/Output/BufferedOutput.php
+++ b/vendor/symfony/console/Output/BufferedOutput.php
@@ -34,7 +34,7 @@ class BufferedOutput extends Output
/**
* {@inheritdoc}
*/
- protected function doWrite($message, $newline)
+ protected function doWrite(string $message, bool $newline)
{
$this->buffer .= $message;
diff --git a/vendor/symfony/console/Output/ConsoleOutput.php b/vendor/symfony/console/Output/ConsoleOutput.php
index 484fcbdea..f19f9ebf4 100644
--- a/vendor/symfony/console/Output/ConsoleOutput.php
+++ b/vendor/symfony/console/Output/ConsoleOutput.php
@@ -67,7 +67,7 @@ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
/**
* {@inheritdoc}
*/
- public function setDecorated($decorated)
+ public function setDecorated(bool $decorated)
{
parent::setDecorated($decorated);
$this->stderr->setDecorated($decorated);
@@ -85,7 +85,7 @@ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
/**
* {@inheritdoc}
*/
- public function setVerbosity($level)
+ public function setVerbosity(int $level)
{
parent::setVerbosity($level);
$this->stderr->setVerbosity($level);
diff --git a/vendor/symfony/console/Output/ConsoleOutputInterface.php b/vendor/symfony/console/Output/ConsoleOutputInterface.php
index f4c2fa623..6b6635f58 100644
--- a/vendor/symfony/console/Output/ConsoleOutputInterface.php
+++ b/vendor/symfony/console/Output/ConsoleOutputInterface.php
@@ -16,8 +16,6 @@ namespace Symfony\Component\Console\Output;
* This adds information about stderr and section output stream.
*
* @author Dariusz Górecki
- *
- * @method ConsoleSectionOutput section() Creates a new output section
*/
interface ConsoleOutputInterface extends OutputInterface
{
@@ -29,4 +27,6 @@ interface ConsoleOutputInterface extends OutputInterface
public function getErrorOutput();
public function setErrorOutput(OutputInterface $error);
+
+ public function section(): ConsoleSectionOutput;
}
diff --git a/vendor/symfony/console/Output/ConsoleSectionOutput.php b/vendor/symfony/console/Output/ConsoleSectionOutput.php
index c19edbf95..8f1649758 100644
--- a/vendor/symfony/console/Output/ConsoleSectionOutput.php
+++ b/vendor/symfony/console/Output/ConsoleSectionOutput.php
@@ -92,7 +92,7 @@ class ConsoleSectionOutput extends StreamOutput
/**
* {@inheritdoc}
*/
- protected function doWrite($message, $newline)
+ protected function doWrite(string $message, bool $newline)
{
if (!$this->isDecorated()) {
parent::doWrite($message, $newline);
@@ -136,8 +136,8 @@ class ConsoleSectionOutput extends StreamOutput
return implode('', array_reverse($erasedContent));
}
- private function getDisplayLength(string $text): string
+ private function getDisplayLength(string $text): int
{
- return Helper::strlenWithoutDecoration($this->getFormatter(), str_replace("\t", ' ', $text));
+ return Helper::width(Helper::removeDecoration($this->getFormatter(), str_replace("\t", ' ', $text)));
}
}
diff --git a/vendor/symfony/console/Output/NullOutput.php b/vendor/symfony/console/Output/NullOutput.php
index 218f285bf..3bbe63ea0 100644
--- a/vendor/symfony/console/Output/NullOutput.php
+++ b/vendor/symfony/console/Output/NullOutput.php
@@ -11,7 +11,7 @@
namespace Symfony\Component\Console\Output;
-use Symfony\Component\Console\Formatter\OutputFormatter;
+use Symfony\Component\Console\Formatter\NullOutputFormatter;
use Symfony\Component\Console\Formatter\OutputFormatterInterface;
/**
@@ -24,6 +24,8 @@ use Symfony\Component\Console\Formatter\OutputFormatterInterface;
*/
class NullOutput implements OutputInterface
{
+ private $formatter;
+
/**
* {@inheritdoc}
*/
@@ -37,14 +39,17 @@ class NullOutput implements OutputInterface
*/
public function getFormatter()
{
+ if ($this->formatter) {
+ return $this->formatter;
+ }
// to comply with the interface we must return a OutputFormatterInterface
- return new OutputFormatter();
+ return $this->formatter = new NullOutputFormatter();
}
/**
* {@inheritdoc}
*/
- public function setDecorated($decorated)
+ public function setDecorated(bool $decorated)
{
// do nothing
}
@@ -60,7 +65,7 @@ class NullOutput implements OutputInterface
/**
* {@inheritdoc}
*/
- public function setVerbosity($level)
+ public function setVerbosity(int $level)
{
// do nothing
}
@@ -108,7 +113,7 @@ class NullOutput implements OutputInterface
/**
* {@inheritdoc}
*/
- public function writeln($messages, $options = self::OUTPUT_NORMAL)
+ public function writeln($messages, int $options = self::OUTPUT_NORMAL)
{
// do nothing
}
@@ -116,7 +121,7 @@ class NullOutput implements OutputInterface
/**
* {@inheritdoc}
*/
- public function write($messages, $newline = false, $options = self::OUTPUT_NORMAL)
+ public function write($messages, bool $newline = false, int $options = self::OUTPUT_NORMAL)
{
// do nothing
}
diff --git a/vendor/symfony/console/Output/Output.php b/vendor/symfony/console/Output/Output.php
index fb838f053..d7c5fb2d1 100644
--- a/vendor/symfony/console/Output/Output.php
+++ b/vendor/symfony/console/Output/Output.php
@@ -33,13 +33,13 @@ abstract class Output implements OutputInterface
private $formatter;
/**
- * @param int $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface)
+ * @param int|null $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface)
* @param bool $decorated Whether to decorate messages
* @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter)
*/
public function __construct(?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, OutputFormatterInterface $formatter = null)
{
- $this->verbosity = null === $verbosity ? self::VERBOSITY_NORMAL : $verbosity;
+ $this->verbosity = $verbosity ?? self::VERBOSITY_NORMAL;
$this->formatter = $formatter ?? new OutputFormatter();
$this->formatter->setDecorated($decorated);
}
@@ -63,7 +63,7 @@ abstract class Output implements OutputInterface
/**
* {@inheritdoc}
*/
- public function setDecorated($decorated)
+ public function setDecorated(bool $decorated)
{
$this->formatter->setDecorated($decorated);
}
@@ -79,9 +79,9 @@ abstract class Output implements OutputInterface
/**
* {@inheritdoc}
*/
- public function setVerbosity($level)
+ public function setVerbosity(int $level)
{
- $this->verbosity = (int) $level;
+ $this->verbosity = $level;
}
/**
@@ -127,7 +127,7 @@ abstract class Output implements OutputInterface
/**
* {@inheritdoc}
*/
- public function writeln($messages, $options = self::OUTPUT_NORMAL)
+ public function writeln($messages, int $options = self::OUTPUT_NORMAL)
{
$this->write($messages, true, $options);
}
@@ -135,7 +135,7 @@ abstract class Output implements OutputInterface
/**
* {@inheritdoc}
*/
- public function write($messages, $newline = false, $options = self::OUTPUT_NORMAL)
+ public function write($messages, bool $newline = false, int $options = self::OUTPUT_NORMAL)
{
if (!is_iterable($messages)) {
$messages = [$messages];
@@ -169,9 +169,6 @@ abstract class Output implements OutputInterface
/**
* Writes a message to the output.
- *
- * @param string $message A message to write to the output
- * @param bool $newline Whether to add a newline or not
*/
- abstract protected function doWrite($message, $newline);
+ abstract protected function doWrite(string $message, bool $newline);
}
diff --git a/vendor/symfony/console/Output/OutputInterface.php b/vendor/symfony/console/Output/OutputInterface.php
index 671d5bd78..55caab80b 100644
--- a/vendor/symfony/console/Output/OutputInterface.php
+++ b/vendor/symfony/console/Output/OutputInterface.php
@@ -37,7 +37,7 @@ interface OutputInterface
* @param bool $newline Whether to add a newline
* @param int $options A bitmask of options (one of the OUTPUT or VERBOSITY constants), 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL
*/
- public function write($messages, $newline = false, $options = 0);
+ public function write($messages, bool $newline = false, int $options = 0);
/**
* Writes a message to the output and adds a newline at the end.
@@ -45,61 +45,57 @@ interface OutputInterface
* @param string|iterable $messages The message as an iterable of strings or a single string
* @param int $options A bitmask of options (one of the OUTPUT or VERBOSITY constants), 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL
*/
- public function writeln($messages, $options = 0);
+ public function writeln($messages, int $options = 0);
/**
* Sets the verbosity of the output.
- *
- * @param int $level The level of verbosity (one of the VERBOSITY constants)
*/
- public function setVerbosity($level);
+ public function setVerbosity(int $level);
/**
* Gets the current verbosity of the output.
*
- * @return int The current level of verbosity (one of the VERBOSITY constants)
+ * @return int
*/
public function getVerbosity();
/**
* Returns whether verbosity is quiet (-q).
*
- * @return bool true if verbosity is set to VERBOSITY_QUIET, false otherwise
+ * @return bool
*/
public function isQuiet();
/**
* Returns whether verbosity is verbose (-v).
*
- * @return bool true if verbosity is set to VERBOSITY_VERBOSE, false otherwise
+ * @return bool
*/
public function isVerbose();
/**
* Returns whether verbosity is very verbose (-vv).
*
- * @return bool true if verbosity is set to VERBOSITY_VERY_VERBOSE, false otherwise
+ * @return bool
*/
public function isVeryVerbose();
/**
* Returns whether verbosity is debug (-vvv).
*
- * @return bool true if verbosity is set to VERBOSITY_DEBUG, false otherwise
+ * @return bool
*/
public function isDebug();
/**
* Sets the decorated flag.
- *
- * @param bool $decorated Whether to decorate the messages
*/
- public function setDecorated($decorated);
+ public function setDecorated(bool $decorated);
/**
* Gets the decorated flag.
*
- * @return bool true if the output will decorate messages, false otherwise
+ * @return bool
*/
public function isDecorated();
diff --git a/vendor/symfony/console/Output/StreamOutput.php b/vendor/symfony/console/Output/StreamOutput.php
index 9c2243644..7f5551827 100644
--- a/vendor/symfony/console/Output/StreamOutput.php
+++ b/vendor/symfony/console/Output/StreamOutput.php
@@ -57,7 +57,7 @@ class StreamOutput extends Output
/**
* Gets the stream attached to this StreamOutput instance.
*
- * @return resource A stream resource
+ * @return resource
*/
public function getStream()
{
@@ -67,7 +67,7 @@ class StreamOutput extends Output
/**
* {@inheritdoc}
*/
- protected function doWrite($message, $newline)
+ protected function doWrite(string $message, bool $newline)
{
if ($newline) {
$message .= \PHP_EOL;
@@ -110,16 +110,6 @@ class StreamOutput extends Output
|| 'xterm' === getenv('TERM');
}
- if (\function_exists('stream_isatty')) {
- return @stream_isatty($this->stream);
- }
-
- if (\function_exists('posix_isatty')) {
- return @posix_isatty($this->stream);
- }
-
- $stat = @fstat($this->stream);
- // Check if formatted mode is S_IFCHR
- return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;
+ return stream_isatty($this->stream);
}
}
diff --git a/vendor/symfony/console/Output/TrimmedBufferOutput.php b/vendor/symfony/console/Output/TrimmedBufferOutput.php
index 87c04a892..3f4d375f4 100644
--- a/vendor/symfony/console/Output/TrimmedBufferOutput.php
+++ b/vendor/symfony/console/Output/TrimmedBufferOutput.php
@@ -50,7 +50,7 @@ class TrimmedBufferOutput extends Output
/**
* {@inheritdoc}
*/
- protected function doWrite($message, $newline)
+ protected function doWrite(string $message, bool $newline)
{
$this->buffer .= $message;
diff --git a/vendor/symfony/console/Question/ChoiceQuestion.php b/vendor/symfony/console/Question/ChoiceQuestion.php
index 6247ca716..bf1f90487 100644
--- a/vendor/symfony/console/Question/ChoiceQuestion.php
+++ b/vendor/symfony/console/Question/ChoiceQuestion.php
@@ -58,11 +58,9 @@ class ChoiceQuestion extends Question
*
* When multiselect is set to true, multiple choices can be answered.
*
- * @param bool $multiselect
- *
* @return $this
*/
- public function setMultiselect($multiselect)
+ public function setMultiselect(bool $multiselect)
{
$this->multiselect = $multiselect;
$this->setValidator($this->getDefaultValidator());
@@ -93,11 +91,9 @@ class ChoiceQuestion extends Question
/**
* Sets the prompt for choices.
*
- * @param string $prompt
- *
* @return $this
*/
- public function setPrompt($prompt)
+ public function setPrompt(string $prompt)
{
$this->prompt = $prompt;
@@ -109,11 +105,9 @@ class ChoiceQuestion extends Question
*
* The error message has a string placeholder (%s) for the invalid value.
*
- * @param string $errorMessage
- *
* @return $this
*/
- public function setErrorMessage($errorMessage)
+ public function setErrorMessage(string $errorMessage)
{
$this->errorMessage = $errorMessage;
$this->setValidator($this->getDefaultValidator());
@@ -175,7 +169,8 @@ class ChoiceQuestion extends Question
throw new InvalidArgumentException(sprintf($errorMessage, $value));
}
- $multiselectChoices[] = (string) $result;
+ // For associative choices, consistently return the key as string:
+ $multiselectChoices[] = $isAssoc ? (string) $result : $result;
}
if ($multiselect) {
diff --git a/vendor/symfony/console/Question/Question.php b/vendor/symfony/console/Question/Question.php
index cc108018f..3a73f04b2 100644
--- a/vendor/symfony/console/Question/Question.php
+++ b/vendor/symfony/console/Question/Question.php
@@ -30,6 +30,7 @@ class Question
private $default;
private $normalizer;
private $trimmable = true;
+ private $multiline = false;
/**
* @param string $question The question to ask to the user
@@ -61,6 +62,26 @@ class Question
return $this->default;
}
+ /**
+ * Returns whether the user response accepts newline characters.
+ */
+ public function isMultiline(): bool
+ {
+ return $this->multiline;
+ }
+
+ /**
+ * Sets whether the user response should accept newline characters.
+ *
+ * @return $this
+ */
+ public function setMultiline(bool $multiline): self
+ {
+ $this->multiline = $multiline;
+
+ return $this;
+ }
+
/**
* Returns whether the user response must be hidden.
*
@@ -74,25 +95,23 @@ class Question
/**
* Sets whether the user response must be hidden or not.
*
- * @param bool $hidden
- *
* @return $this
*
* @throws LogicException In case the autocompleter is also used
*/
- public function setHidden($hidden)
+ public function setHidden(bool $hidden)
{
if ($this->autocompleterCallback) {
throw new LogicException('A hidden question cannot use the autocompleter.');
}
- $this->hidden = (bool) $hidden;
+ $this->hidden = $hidden;
return $this;
}
/**
- * In case the response can not be hidden, whether to fallback on non-hidden question or not.
+ * In case the response cannot be hidden, whether to fallback on non-hidden question or not.
*
* @return bool
*/
@@ -102,15 +121,13 @@ class Question
}
/**
- * Sets whether to fallback on non-hidden question if the response can not be hidden.
- *
- * @param bool $fallback
+ * Sets whether to fallback on non-hidden question if the response cannot be hidden.
*
* @return $this
*/
- public function setHiddenFallback($fallback)
+ public function setHiddenFallback(bool $fallback)
{
- $this->hiddenFallback = (bool) $fallback;
+ $this->hiddenFallback = $fallback;
return $this;
}
@@ -130,14 +147,11 @@ class Question
/**
* Sets values for the autocompleter.
*
- * @param iterable|null $values
- *
* @return $this
*
- * @throws InvalidArgumentException
* @throws LogicException
*/
- public function setAutocompleterValues($values)
+ public function setAutocompleterValues(?iterable $values)
{
if (\is_array($values)) {
$values = $this->isAssoc($values) ? array_merge(array_keys($values), array_values($values)) : array_values($values);
@@ -150,10 +164,8 @@ class Question
$callback = static function () use ($values, &$valueCache) {
return $valueCache ?? $valueCache = iterator_to_array($values, false);
};
- } elseif (null === $values) {
- $callback = null;
} else {
- throw new InvalidArgumentException('Autocompleter values can be either an array, "null" or a "Traversable" object.');
+ $callback = null;
}
return $this->setAutocompleterCallback($callback);
@@ -212,19 +224,14 @@ class Question
*
* Null means an unlimited number of attempts.
*
- * @param int|null $attempts
- *
* @return $this
*
* @throws InvalidArgumentException in case the number of attempts is invalid
*/
- public function setMaxAttempts($attempts)
+ public function setMaxAttempts(?int $attempts)
{
- if (null !== $attempts) {
- $attempts = (int) $attempts;
- if ($attempts < 1) {
- throw new InvalidArgumentException('Maximum number of attempts must be a positive value.');
- }
+ if (null !== $attempts && $attempts < 1) {
+ throw new InvalidArgumentException('Maximum number of attempts must be a positive value.');
}
$this->attempts = $attempts;
@@ -270,7 +277,7 @@ class Question
return $this->normalizer;
}
- protected function isAssoc($array)
+ protected function isAssoc(array $array)
{
return (bool) \count(array_filter(array_keys($array), 'is_string'));
}
diff --git a/vendor/symfony/console/README.md b/vendor/symfony/console/README.md
index c89b4a1a2..c4c129989 100644
--- a/vendor/symfony/console/README.md
+++ b/vendor/symfony/console/README.md
@@ -4,6 +4,18 @@ Console Component
The Console component eases the creation of beautiful and testable command line
interfaces.
+Sponsor
+-------
+
+The Console component for Symfony 5.4/6.0 is [backed][1] by [Les-Tilleuls.coop][2].
+
+Les-Tilleuls.coop is a team of 50+ Symfony experts who can help you design, develop and
+fix your projects. We provide a wide range of professional services including development,
+consulting, coaching, training and audits. We also are highly skilled in JS, Go and DevOps.
+We are a worker cooperative!
+
+Help Symfony by [sponsoring][3] its development!
+
Resources
---------
@@ -18,3 +30,7 @@ Credits
`Resources/bin/hiddeninput.exe` is a third party binary provided within this
component. Find sources and license at https://github.com/Seldaek/hidden-input.
+
+[1]: https://symfony.com/backers
+[2]: https://les-tilleuls.coop
+[3]: https://symfony.com/sponsor
diff --git a/vendor/symfony/console/Resources/completion.bash b/vendor/symfony/console/Resources/completion.bash
new file mode 100644
index 000000000..64b87ccf7
--- /dev/null
+++ b/vendor/symfony/console/Resources/completion.bash
@@ -0,0 +1,84 @@
+# This file is part of the Symfony package.
+#
+# (c) Fabien Potencier
+#
+# For the full copyright and license information, please view
+# https://symfony.com/doc/current/contributing/code/license.html
+
+_sf_{{ COMMAND_NAME }}() {
+ # Use newline as only separator to allow space in completion values
+ IFS=$'\n'
+ local sf_cmd="${COMP_WORDS[0]}"
+
+ # for an alias, get the real script behind it
+ sf_cmd_type=$(type -t $sf_cmd)
+ if [[ $sf_cmd_type == "alias" ]]; then
+ sf_cmd=$(alias $sf_cmd | sed -E "s/alias $sf_cmd='(.*)'/\1/")
+ elif [[ $sf_cmd_type == "file" ]]; then
+ sf_cmd=$(type -p $sf_cmd)
+ fi
+
+ if [[ $sf_cmd_type != "function" && ! -x $sf_cmd ]]; then
+ return 1
+ fi
+
+ local cur prev words cword
+ _get_comp_words_by_ref -n := cur prev words cword
+
+ local completecmd=("$sf_cmd" "_complete" "--no-interaction" "-sbash" "-c$cword" "-S{{ VERSION }}")
+ for w in ${words[@]}; do
+ w=$(printf -- '%b' "$w")
+ # remove quotes from typed values
+ quote="${w:0:1}"
+ if [ "$quote" == \' ]; then
+ w="${w%\'}"
+ w="${w#\'}"
+ elif [ "$quote" == \" ]; then
+ w="${w%\"}"
+ w="${w#\"}"
+ fi
+ # empty values are ignored
+ if [ ! -z "$w" ]; then
+ completecmd+=("-i$w")
+ fi
+ done
+
+ local sfcomplete
+ if sfcomplete=$(${completecmd[@]} 2>&1); then
+ local quote suggestions
+ quote=${cur:0:1}
+
+ # Use single quotes by default if suggestions contains backslash (FQCN)
+ if [ "$quote" == '' ] && [[ "$sfcomplete" =~ \\ ]]; then
+ quote=\'
+ fi
+
+ if [ "$quote" == \' ]; then
+ # single quotes: no additional escaping (does not accept ' in values)
+ suggestions=$(for s in $sfcomplete; do printf $'%q%q%q\n' "$quote" "$s" "$quote"; done)
+ elif [ "$quote" == \" ]; then
+ # double quotes: double escaping for \ $ ` "
+ suggestions=$(for s in $sfcomplete; do
+ s=${s//\\/\\\\}
+ s=${s//\$/\\\$}
+ s=${s//\`/\\\`}
+ s=${s//\"/\\\"}
+ printf $'%q%q%q\n' "$quote" "$s" "$quote";
+ done)
+ else
+ # no quotes: double escaping
+ suggestions=$(for s in $sfcomplete; do printf $'%q\n' $(printf '%q' "$s"); done)
+ fi
+ COMPREPLY=($(IFS=$'\n' compgen -W "$suggestions" -- $(printf -- "%q" "$cur")))
+ __ltrim_colon_completions "$cur"
+ else
+ if [[ "$sfcomplete" != *"Command \"_complete\" is not defined."* ]]; then
+ >&2 echo
+ >&2 echo $sfcomplete
+ fi
+
+ return 1
+ fi
+}
+
+complete -F _sf_{{ COMMAND_NAME }} {{ COMMAND_NAME }}
diff --git a/vendor/symfony/console/SignalRegistry/SignalRegistry.php b/vendor/symfony/console/SignalRegistry/SignalRegistry.php
new file mode 100644
index 000000000..6bee24a42
--- /dev/null
+++ b/vendor/symfony/console/SignalRegistry/SignalRegistry.php
@@ -0,0 +1,65 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Console\SignalRegistry;
+
+final class SignalRegistry
+{
+ private $signalHandlers = [];
+
+ public function __construct()
+ {
+ if (\function_exists('pcntl_async_signals')) {
+ pcntl_async_signals(true);
+ }
+ }
+
+ public function register(int $signal, callable $signalHandler): void
+ {
+ if (!isset($this->signalHandlers[$signal])) {
+ $previousCallback = pcntl_signal_get_handler($signal);
+
+ if (\is_callable($previousCallback)) {
+ $this->signalHandlers[$signal][] = $previousCallback;
+ }
+ }
+
+ $this->signalHandlers[$signal][] = $signalHandler;
+
+ pcntl_signal($signal, [$this, 'handle']);
+ }
+
+ public static function isSupported(): bool
+ {
+ if (!\function_exists('pcntl_signal')) {
+ return false;
+ }
+
+ if (\in_array('pcntl_signal', explode(',', \ini_get('disable_functions')))) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * @internal
+ */
+ public function handle(int $signal): void
+ {
+ $count = \count($this->signalHandlers[$signal]);
+
+ foreach ($this->signalHandlers[$signal] as $i => $signalHandler) {
+ $hasNext = $i !== $count - 1;
+ $signalHandler($signal, $hasNext);
+ }
+ }
+}
diff --git a/vendor/symfony/console/SingleCommandApplication.php b/vendor/symfony/console/SingleCommandApplication.php
new file mode 100644
index 000000000..e93c1821b
--- /dev/null
+++ b/vendor/symfony/console/SingleCommandApplication.php
@@ -0,0 +1,72 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Console;
+
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * @author Grégoire Pineau
+ */
+class SingleCommandApplication extends Command
+{
+ private $version = 'UNKNOWN';
+ private $autoExit = true;
+ private $running = false;
+
+ /**
+ * @return $this
+ */
+ public function setVersion(string $version): self
+ {
+ $this->version = $version;
+
+ return $this;
+ }
+
+ /**
+ * @final
+ *
+ * @return $this
+ */
+ public function setAutoExit(bool $autoExit): self
+ {
+ $this->autoExit = $autoExit;
+
+ return $this;
+ }
+
+ public function run(InputInterface $input = null, OutputInterface $output = null): int
+ {
+ if ($this->running) {
+ return parent::run($input, $output);
+ }
+
+ // We use the command name as the application name
+ $application = new Application($this->getName() ?: 'UNKNOWN', $this->version);
+ $application->setAutoExit($this->autoExit);
+ // Fix the usage of the command displayed with "--help"
+ $this->setName($_SERVER['argv'][0]);
+ $application->add($this);
+ $application->setDefaultCommand($this->getName(), true);
+
+ $this->running = true;
+ try {
+ $ret = $application->run($input, $output);
+ } finally {
+ $this->running = false;
+ }
+
+ return $ret ?? 1;
+ }
+}
diff --git a/vendor/symfony/console/Style/OutputStyle.php b/vendor/symfony/console/Style/OutputStyle.php
index 14d2d60b2..67a98ff07 100644
--- a/vendor/symfony/console/Style/OutputStyle.php
+++ b/vendor/symfony/console/Style/OutputStyle.php
@@ -33,17 +33,15 @@ abstract class OutputStyle implements OutputInterface, StyleInterface
/**
* {@inheritdoc}
*/
- public function newLine($count = 1)
+ public function newLine(int $count = 1)
{
$this->output->write(str_repeat(\PHP_EOL, $count));
}
/**
- * @param int $max
- *
* @return ProgressBar
*/
- public function createProgressBar($max = 0)
+ public function createProgressBar(int $max = 0)
{
return new ProgressBar($this->output, $max);
}
@@ -51,7 +49,7 @@ abstract class OutputStyle implements OutputInterface, StyleInterface
/**
* {@inheritdoc}
*/
- public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL)
+ public function write($messages, bool $newline = false, int $type = self::OUTPUT_NORMAL)
{
$this->output->write($messages, $newline, $type);
}
@@ -59,7 +57,7 @@ abstract class OutputStyle implements OutputInterface, StyleInterface
/**
* {@inheritdoc}
*/
- public function writeln($messages, $type = self::OUTPUT_NORMAL)
+ public function writeln($messages, int $type = self::OUTPUT_NORMAL)
{
$this->output->writeln($messages, $type);
}
@@ -67,7 +65,7 @@ abstract class OutputStyle implements OutputInterface, StyleInterface
/**
* {@inheritdoc}
*/
- public function setVerbosity($level)
+ public function setVerbosity(int $level)
{
$this->output->setVerbosity($level);
}
@@ -83,7 +81,7 @@ abstract class OutputStyle implements OutputInterface, StyleInterface
/**
* {@inheritdoc}
*/
- public function setDecorated($decorated)
+ public function setDecorated(bool $decorated)
{
$this->output->setDecorated($decorated);
}
diff --git a/vendor/symfony/console/Style/StyleInterface.php b/vendor/symfony/console/Style/StyleInterface.php
index 3b5b8af51..38d23b77e 100644
--- a/vendor/symfony/console/Style/StyleInterface.php
+++ b/vendor/symfony/console/Style/StyleInterface.php
@@ -20,17 +20,13 @@ interface StyleInterface
{
/**
* Formats a command title.
- *
- * @param string $message
*/
- public function title($message);
+ public function title(string $message);
/**
* Formats a section title.
- *
- * @param string $message
*/
- public function section($message);
+ public function section(string $message);
/**
* Formats a list.
@@ -87,64 +83,47 @@ interface StyleInterface
/**
* Asks a question.
*
- * @param string $question
- * @param string|null $default
- * @param callable|null $validator
- *
* @return mixed
*/
- public function ask($question, $default = null, $validator = null);
+ public function ask(string $question, string $default = null, callable $validator = null);
/**
* Asks a question with the user input hidden.
*
- * @param string $question
- * @param callable|null $validator
- *
* @return mixed
*/
- public function askHidden($question, $validator = null);
+ public function askHidden(string $question, callable $validator = null);
/**
* Asks for confirmation.
*
- * @param string $question
- * @param bool $default
- *
* @return bool
*/
- public function confirm($question, $default = true);
+ public function confirm(string $question, bool $default = true);
/**
* Asks a choice question.
*
- * @param string $question
* @param string|int|null $default
*
* @return mixed
*/
- public function choice($question, array $choices, $default = null);
+ public function choice(string $question, array $choices, $default = null);
/**
* Add newline(s).
- *
- * @param int $count The number of newlines
*/
- public function newLine($count = 1);
+ public function newLine(int $count = 1);
/**
* Starts the progress output.
- *
- * @param int $max Maximum steps (0 if unknown)
*/
- public function progressStart($max = 0);
+ public function progressStart(int $max = 0);
/**
* Advances the progress output X steps.
- *
- * @param int $step Number of steps to advance
*/
- public function progressAdvance($step = 1);
+ public function progressAdvance(int $step = 1);
/**
* Finishes the progress output.
diff --git a/vendor/symfony/console/Style/SymfonyStyle.php b/vendor/symfony/console/Style/SymfonyStyle.php
index 66db3ad5a..e3c5ac8e7 100644
--- a/vendor/symfony/console/Style/SymfonyStyle.php
+++ b/vendor/symfony/console/Style/SymfonyStyle.php
@@ -21,6 +21,7 @@ use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Helper\TableCell;
use Symfony\Component\Console\Helper\TableSeparator;
use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Output\TrimmedBufferOutput;
use Symfony\Component\Console\Question\ChoiceQuestion;
@@ -38,6 +39,7 @@ class SymfonyStyle extends OutputStyle
public const MAX_LINE_LENGTH = 120;
private $input;
+ private $output;
private $questionHelper;
private $progressBar;
private $lineLength;
@@ -51,20 +53,15 @@ class SymfonyStyle extends OutputStyle
$width = (new Terminal())->getWidth() ?: self::MAX_LINE_LENGTH;
$this->lineLength = min($width - (int) (\DIRECTORY_SEPARATOR === '\\'), self::MAX_LINE_LENGTH);
- parent::__construct($output);
+ parent::__construct($this->output = $output);
}
/**
* Formats a message as a block of text.
*
* @param string|array $messages The message to write in the block
- * @param string|null $type The block type (added in [] on first line)
- * @param string|null $style The style to apply to the whole block
- * @param string $prefix The prefix for the block
- * @param bool $padding Whether to add vertical padding
- * @param bool $escape Whether to escape the message
*/
- public function block($messages, $type = null, $style = null, $prefix = ' ', $padding = false, $escape = true)
+ public function block($messages, string $type = null, string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = true)
{
$messages = \is_array($messages) ? array_values($messages) : [$messages];
@@ -76,12 +73,12 @@ class SymfonyStyle extends OutputStyle
/**
* {@inheritdoc}
*/
- public function title($message)
+ public function title(string $message)
{
$this->autoPrependBlock();
$this->writeln([
sprintf('%s>', OutputFormatter::escapeTrailingBackslash($message)),
- sprintf('%s>', str_repeat('=', Helper::strlenWithoutDecoration($this->getFormatter(), $message))),
+ sprintf('%s>', str_repeat('=', Helper::width(Helper::removeDecoration($this->getFormatter(), $message)))),
]);
$this->newLine();
}
@@ -89,12 +86,12 @@ class SymfonyStyle extends OutputStyle
/**
* {@inheritdoc}
*/
- public function section($message)
+ public function section(string $message)
{
$this->autoPrependBlock();
$this->writeln([
sprintf('%s>', OutputFormatter::escapeTrailingBackslash($message)),
- sprintf('%s>', str_repeat('-', Helper::strlenWithoutDecoration($this->getFormatter(), $message))),
+ sprintf('%s>', str_repeat('-', Helper::width(Helper::removeDecoration($this->getFormatter(), $message)))),
]);
$this->newLine();
}
@@ -168,6 +165,16 @@ class SymfonyStyle extends OutputStyle
$this->block($message, 'NOTE', 'fg=yellow', ' ! ');
}
+ /**
+ * Formats an info message.
+ *
+ * @param string|array $message
+ */
+ public function info($message)
+ {
+ $this->block($message, 'INFO', 'fg=green', ' ', true);
+ }
+
/**
* {@inheritdoc}
*/
@@ -181,15 +188,12 @@ class SymfonyStyle extends OutputStyle
*/
public function table(array $headers, array $rows)
{
- $style = clone Table::getStyleDefinition('symfony-style-guide');
- $style->setCellHeaderFormat('%s');
+ $this->createTable()
+ ->setHeaders($headers)
+ ->setRows($rows)
+ ->render()
+ ;
- $table = new Table($this);
- $table->setHeaders($headers);
- $table->setRows($rows);
- $table->setStyle($style);
-
- $table->render();
$this->newLine();
}
@@ -198,16 +202,13 @@ class SymfonyStyle extends OutputStyle
*/
public function horizontalTable(array $headers, array $rows)
{
- $style = clone Table::getStyleDefinition('symfony-style-guide');
- $style->setCellHeaderFormat('%s');
+ $this->createTable()
+ ->setHorizontal(true)
+ ->setHeaders($headers)
+ ->setRows($rows)
+ ->render()
+ ;
- $table = new Table($this);
- $table->setHeaders($headers);
- $table->setRows($rows);
- $table->setStyle($style);
- $table->setHorizontal(true);
-
- $table->render();
$this->newLine();
}
@@ -223,10 +224,6 @@ class SymfonyStyle extends OutputStyle
*/
public function definitionList(...$list)
{
- $style = clone Table::getStyleDefinition('symfony-style-guide');
- $style->setCellHeaderFormat('%s');
-
- $table = new Table($this);
$headers = [];
$row = [];
foreach ($list as $value) {
@@ -247,19 +244,13 @@ class SymfonyStyle extends OutputStyle
$row[] = current($value);
}
- $table->setHeaders($headers);
- $table->setRows([$row]);
- $table->setHorizontal();
- $table->setStyle($style);
-
- $table->render();
- $this->newLine();
+ $this->horizontalTable($headers, [$row]);
}
/**
* {@inheritdoc}
*/
- public function ask($question, $default = null, $validator = null)
+ public function ask(string $question, string $default = null, callable $validator = null)
{
$question = new Question($question, $default);
$question->setValidator($validator);
@@ -270,7 +261,7 @@ class SymfonyStyle extends OutputStyle
/**
* {@inheritdoc}
*/
- public function askHidden($question, $validator = null)
+ public function askHidden(string $question, callable $validator = null)
{
$question = new Question($question);
@@ -283,7 +274,7 @@ class SymfonyStyle extends OutputStyle
/**
* {@inheritdoc}
*/
- public function confirm($question, $default = true)
+ public function confirm(string $question, bool $default = true)
{
return $this->askQuestion(new ConfirmationQuestion($question, $default));
}
@@ -291,7 +282,7 @@ class SymfonyStyle extends OutputStyle
/**
* {@inheritdoc}
*/
- public function choice($question, array $choices, $default = null)
+ public function choice(string $question, array $choices, $default = null)
{
if (null !== $default) {
$values = array_flip($choices);
@@ -304,7 +295,7 @@ class SymfonyStyle extends OutputStyle
/**
* {@inheritdoc}
*/
- public function progressStart($max = 0)
+ public function progressStart(int $max = 0)
{
$this->progressBar = $this->createProgressBar($max);
$this->progressBar->start();
@@ -313,7 +304,7 @@ class SymfonyStyle extends OutputStyle
/**
* {@inheritdoc}
*/
- public function progressAdvance($step = 1)
+ public function progressAdvance(int $step = 1)
{
$this->getProgressBar()->advance($step);
}
@@ -331,7 +322,7 @@ class SymfonyStyle extends OutputStyle
/**
* {@inheritdoc}
*/
- public function createProgressBar($max = 0)
+ public function createProgressBar(int $max = 0)
{
$progressBar = parent::createProgressBar($max);
@@ -344,6 +335,16 @@ class SymfonyStyle extends OutputStyle
return $progressBar;
}
+ /**
+ * @see ProgressBar::iterate()
+ */
+ public function progressIterate(iterable $iterable, int $max = null): iterable
+ {
+ yield from $this->createProgressBar()->iterate($iterable, $max);
+
+ $this->newLine(2);
+ }
+
/**
* @return mixed
*/
@@ -370,7 +371,7 @@ class SymfonyStyle extends OutputStyle
/**
* {@inheritdoc}
*/
- public function writeln($messages, $type = self::OUTPUT_NORMAL)
+ public function writeln($messages, int $type = self::OUTPUT_NORMAL)
{
if (!is_iterable($messages)) {
$messages = [$messages];
@@ -385,7 +386,7 @@ class SymfonyStyle extends OutputStyle
/**
* {@inheritdoc}
*/
- public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL)
+ public function write($messages, bool $newline = false, int $type = self::OUTPUT_NORMAL)
{
if (!is_iterable($messages)) {
$messages = [$messages];
@@ -400,7 +401,7 @@ class SymfonyStyle extends OutputStyle
/**
* {@inheritdoc}
*/
- public function newLine($count = 1)
+ public function newLine(int $count = 1)
{
parent::newLine($count);
$this->bufferedOutput->write(str_repeat("\n", $count));
@@ -416,6 +417,15 @@ class SymfonyStyle extends OutputStyle
return new self($this->input, $this->getErrorOutput());
}
+ public function createTable(): Table
+ {
+ $output = $this->output instanceof ConsoleOutputInterface ? $this->output->section() : $this->output;
+ $style = clone Table::getStyleDefinition('symfony-style-guide');
+ $style->setCellHeaderFormat('%s');
+
+ return (new Table($output))->setStyle($style);
+ }
+
private function getProgressBar(): ProgressBar
{
if (!$this->progressBar) {
@@ -430,18 +440,18 @@ class SymfonyStyle extends OutputStyle
$chars = substr(str_replace(\PHP_EOL, "\n", $this->bufferedOutput->fetch()), -2);
if (!isset($chars[0])) {
- $this->newLine(); //empty history, so we should start with a new line.
+ $this->newLine(); // empty history, so we should start with a new line.
return;
}
- //Prepend new line for each non LF chars (This means no blank line was output before)
+ // Prepend new line for each non LF chars (This means no blank line was output before)
$this->newLine(2 - substr_count($chars, "\n"));
}
private function autoPrependText(): void
{
$fetched = $this->bufferedOutput->fetch();
- //Prepend new line if last char isn't EOL:
+ // Prepend new line if last char isn't EOL:
if (!str_ends_with($fetched, "\n")) {
$this->newLine();
}
@@ -456,7 +466,7 @@ class SymfonyStyle extends OutputStyle
private function createBlock(iterable $messages, string $type = null, string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = false): array
{
$indentLength = 0;
- $prefixLength = Helper::strlenWithoutDecoration($this->getFormatter(), $prefix);
+ $prefixLength = Helper::width(Helper::removeDecoration($this->getFormatter(), $prefix));
$lines = [];
if (null !== $type) {
@@ -471,7 +481,7 @@ class SymfonyStyle extends OutputStyle
$message = OutputFormatter::escape($message);
}
- $decorationLength = Helper::strlen($message) - Helper::strlenWithoutDecoration($this->getFormatter(), $message);
+ $decorationLength = Helper::width($message) - Helper::width(Helper::removeDecoration($this->getFormatter(), $message));
$messageLineLength = min($this->lineLength - $prefixLength - $indentLength + $decorationLength, $this->lineLength);
$messageLines = explode(\PHP_EOL, wordwrap($message, $messageLineLength, \PHP_EOL, true));
foreach ($messageLines as $messageLine) {
@@ -496,7 +506,7 @@ class SymfonyStyle extends OutputStyle
}
$line = $prefix.$line;
- $line .= str_repeat(' ', max($this->lineLength - Helper::strlenWithoutDecoration($this->getFormatter(), $line), 0));
+ $line .= str_repeat(' ', max($this->lineLength - Helper::width(Helper::removeDecoration($this->getFormatter(), $line)), 0));
if ($style) {
$line = sprintf('<%s>%s>', $style, $line);
diff --git a/vendor/symfony/console/Terminal.php b/vendor/symfony/console/Terminal.php
index 5e5a3c2f7..b91e8afc5 100644
--- a/vendor/symfony/console/Terminal.php
+++ b/vendor/symfony/console/Terminal.php
@@ -57,29 +57,26 @@ class Terminal
/**
* @internal
- *
- * @return bool
*/
- public static function hasSttyAvailable()
+ public static function hasSttyAvailable(): bool
{
if (null !== self::$stty) {
return self::$stty;
}
- // skip check if exec function is disabled
- if (!\function_exists('exec')) {
+ // skip check if shell_exec function is disabled
+ if (!\function_exists('shell_exec')) {
return false;
}
- exec('stty 2>&1', $output, $exitcode);
-
- return self::$stty = 0 === $exitcode;
+ return self::$stty = (bool) shell_exec('stty 2> '.('\\' === \DIRECTORY_SEPARATOR ? 'NUL' : '/dev/null'));
}
private static function initDimensions()
{
if ('\\' === \DIRECTORY_SEPARATOR) {
- if (preg_match('/^(\d+)x(\d+)(?: \((\d+)x(\d+)\))?$/', trim(getenv('ANSICON')), $matches)) {
+ $ansicon = getenv('ANSICON');
+ if (false !== $ansicon && preg_match('/^(\d+)x(\d+)(?: \((\d+)x(\d+)\))?$/', trim($ansicon), $matches)) {
// extract [w, H] from "wxh (WxH)"
// or [w, h] from "wxh"
self::$width = (int) $matches[1];
@@ -159,6 +156,8 @@ class Terminal
2 => ['pipe', 'w'],
];
+ $cp = \function_exists('sapi_windows_cp_set') ? sapi_windows_cp_get() : 0;
+
$process = proc_open($command, $descriptorspec, $pipes, null, null, ['suppress_errors' => true]);
if (!\is_resource($process)) {
return null;
@@ -169,6 +168,10 @@ class Terminal
fclose($pipes[2]);
proc_close($process);
+ if ($cp) {
+ sapi_windows_cp_set($cp);
+ }
+
return $info;
}
}
diff --git a/vendor/symfony/console/Tester/ApplicationTester.php b/vendor/symfony/console/Tester/ApplicationTester.php
index 4f99da18d..3a262e81c 100644
--- a/vendor/symfony/console/Tester/ApplicationTester.php
+++ b/vendor/symfony/console/Tester/ApplicationTester.php
@@ -29,8 +29,6 @@ class ApplicationTester
use TesterTrait;
private $application;
- private $input;
- private $statusCode;
public function __construct(Application $application)
{
@@ -47,24 +45,41 @@ class ApplicationTester
* * verbosity: Sets the output verbosity flag
* * capture_stderr_separately: Make output of stdOut and stdErr separately available
*
- * @param array $input An array of arguments and options
- * @param array $options An array of options
- *
* @return int The command exit code
*/
- public function run(array $input, $options = [])
+ public function run(array $input, array $options = [])
{
- $this->input = new ArrayInput($input);
- if (isset($options['interactive'])) {
- $this->input->setInteractive($options['interactive']);
+ $prevShellVerbosity = getenv('SHELL_VERBOSITY');
+
+ try {
+ $this->input = new ArrayInput($input);
+ if (isset($options['interactive'])) {
+ $this->input->setInteractive($options['interactive']);
+ }
+
+ if ($this->inputs) {
+ $this->input->setStream(self::createStream($this->inputs));
+ }
+
+ $this->initOutput($options);
+
+ return $this->statusCode = $this->application->run($this->input, $this->output);
+ } finally {
+ // SHELL_VERBOSITY is set by Application::configureIO so we need to unset/reset it
+ // to its previous value to avoid one test's verbosity to spread to the following tests
+ if (false === $prevShellVerbosity) {
+ if (\function_exists('putenv')) {
+ @putenv('SHELL_VERBOSITY');
+ }
+ unset($_ENV['SHELL_VERBOSITY']);
+ unset($_SERVER['SHELL_VERBOSITY']);
+ } else {
+ if (\function_exists('putenv')) {
+ @putenv('SHELL_VERBOSITY='.$prevShellVerbosity);
+ }
+ $_ENV['SHELL_VERBOSITY'] = $prevShellVerbosity;
+ $_SERVER['SHELL_VERBOSITY'] = $prevShellVerbosity;
+ }
}
-
- if ($this->inputs) {
- $this->input->setStream(self::createStream($this->inputs));
- }
-
- $this->initOutput($options);
-
- return $this->statusCode = $this->application->run($this->input, $this->output);
}
}
diff --git a/vendor/symfony/console/Tester/CommandCompletionTester.php b/vendor/symfony/console/Tester/CommandCompletionTester.php
new file mode 100644
index 000000000..ade732752
--- /dev/null
+++ b/vendor/symfony/console/Tester/CommandCompletionTester.php
@@ -0,0 +1,56 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Console\Tester;
+
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Completion\CompletionInput;
+use Symfony\Component\Console\Completion\CompletionSuggestions;
+
+/**
+ * Eases the testing of command completion.
+ *
+ * @author Jérôme Tamarelle
+ */
+class CommandCompletionTester
+{
+ private $command;
+
+ public function __construct(Command $command)
+ {
+ $this->command = $command;
+ }
+
+ /**
+ * Create completion suggestions from input tokens.
+ */
+ public function complete(array $input): array
+ {
+ $currentIndex = \count($input);
+ if ('' === end($input)) {
+ array_pop($input);
+ }
+ array_unshift($input, $this->command->getName());
+
+ $completionInput = CompletionInput::fromTokens($input, $currentIndex);
+ $completionInput->bind($this->command->getDefinition());
+ $suggestions = new CompletionSuggestions();
+
+ $this->command->complete($completionInput, $suggestions);
+
+ $options = [];
+ foreach ($suggestions->getOptionSuggestions() as $option) {
+ $options[] = '--'.$option->getName();
+ }
+
+ return array_map('strval', array_merge($options, $suggestions->getValueSuggestions()));
+ }
+}
diff --git a/vendor/symfony/console/Tester/CommandTester.php b/vendor/symfony/console/Tester/CommandTester.php
index 57efc9a67..6c15c25fb 100644
--- a/vendor/symfony/console/Tester/CommandTester.php
+++ b/vendor/symfony/console/Tester/CommandTester.php
@@ -25,8 +25,6 @@ class CommandTester
use TesterTrait;
private $command;
- private $input;
- private $statusCode;
public function __construct(Command $command)
{
diff --git a/vendor/symfony/console/Tester/Constraint/CommandIsSuccessful.php b/vendor/symfony/console/Tester/Constraint/CommandIsSuccessful.php
new file mode 100644
index 000000000..a47324237
--- /dev/null
+++ b/vendor/symfony/console/Tester/Constraint/CommandIsSuccessful.php
@@ -0,0 +1,55 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Console\Tester\Constraint;
+
+use PHPUnit\Framework\Constraint\Constraint;
+use Symfony\Component\Console\Command\Command;
+
+final class CommandIsSuccessful extends Constraint
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function toString(): string
+ {
+ return 'is successful';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function matches($other): bool
+ {
+ return Command::SUCCESS === $other;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function failureDescription($other): string
+ {
+ return 'the command '.$this->toString();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function additionalFailureDescription($other): string
+ {
+ $mapping = [
+ Command::FAILURE => 'Command failed.',
+ Command::INVALID => 'Command was invalid.',
+ ];
+
+ return $mapping[$other] ?? sprintf('Command returned exit status %d.', $other);
+ }
+}
diff --git a/vendor/symfony/console/Tester/TesterTrait.php b/vendor/symfony/console/Tester/TesterTrait.php
index 27d598559..f454bbf9d 100644
--- a/vendor/symfony/console/Tester/TesterTrait.php
+++ b/vendor/symfony/console/Tester/TesterTrait.php
@@ -11,10 +11,12 @@
namespace Symfony\Component\Console\Tester;
+use PHPUnit\Framework\Assert;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Output\StreamOutput;
+use Symfony\Component\Console\Tester\Constraint\CommandIsSuccessful;
/**
* @author Amrouche Hamza
@@ -25,15 +27,19 @@ trait TesterTrait
private $output;
private $inputs = [];
private $captureStreamsIndependently = false;
+ /** @var InputInterface */
+ private $input;
+ /** @var int */
+ private $statusCode;
/**
* Gets the display returned by the last execution of the command or application.
*
- * @param bool $normalize Whether to normalize end of lines to \n or not
+ * @return string
*
- * @return string The display
+ * @throws \RuntimeException If it's called before the execute method
*/
- public function getDisplay($normalize = false)
+ public function getDisplay(bool $normalize = false)
{
if (null === $this->output) {
throw new \RuntimeException('Output not initialized, did you execute the command before requesting the display?');
@@ -57,7 +63,7 @@ trait TesterTrait
*
* @return string
*/
- public function getErrorOutput($normalize = false)
+ public function getErrorOutput(bool $normalize = false)
{
if (!$this->captureStreamsIndependently) {
throw new \LogicException('The error output is not available when the tester is run without "capture_stderr_separately" option set.');
@@ -77,7 +83,7 @@ trait TesterTrait
/**
* Gets the input instance used by the last execution of the command or application.
*
- * @return InputInterface The current input instance
+ * @return InputInterface
*/
public function getInput()
{
@@ -87,7 +93,7 @@ trait TesterTrait
/**
* Gets the output instance used by the last execution of the command or application.
*
- * @return OutputInterface The current output instance
+ * @return OutputInterface
*/
public function getOutput()
{
@@ -97,13 +103,24 @@ trait TesterTrait
/**
* Gets the status code returned by the last execution of the command or application.
*
- * @return int The status code
+ * @return int
+ *
+ * @throws \RuntimeException If it's called before the execute method
*/
public function getStatusCode()
{
+ if (null === $this->statusCode) {
+ throw new \RuntimeException('Status code not initialized, did you execute the command before requesting the status code?');
+ }
+
return $this->statusCode;
}
+ public function assertCommandIsSuccessful(string $message = ''): void
+ {
+ Assert::assertThat($this->statusCode, new CommandIsSuccessful(), $message);
+ }
+
/**
* Sets the user inputs.
*
diff --git a/vendor/symfony/console/composer.json b/vendor/symfony/console/composer.json
index 90cbd24f5..4fa4964a1 100644
--- a/vendor/symfony/console/composer.json
+++ b/vendor/symfony/console/composer.json
@@ -2,7 +2,7 @@
"name": "symfony/console",
"type": "library",
"description": "Eases the creation of beautiful and testable command line interfaces",
- "keywords": [],
+ "keywords": ["console", "cli", "command-line", "terminal"],
"homepage": "https://symfony.com",
"license": "MIT",
"authors": [
@@ -16,19 +16,21 @@
}
],
"require": {
- "php": ">=7.1.3",
+ "php": ">=7.2.5",
+ "symfony/deprecation-contracts": "^2.1|^3",
"symfony/polyfill-mbstring": "~1.0",
- "symfony/polyfill-php73": "^1.8",
+ "symfony/polyfill-php73": "^1.9",
"symfony/polyfill-php80": "^1.16",
- "symfony/service-contracts": "^1.1|^2"
+ "symfony/service-contracts": "^1.1|^2|^3",
+ "symfony/string": "^5.1|^6.0"
},
"require-dev": {
- "symfony/config": "^3.4|^4.0|^5.0",
- "symfony/event-dispatcher": "^4.3",
- "symfony/dependency-injection": "^3.4|^4.0|^5.0",
- "symfony/lock": "^4.4|^5.0",
- "symfony/process": "^3.4|^4.0|^5.0",
- "symfony/var-dumper": "^4.3|^5.0",
+ "symfony/config": "^4.4|^5.0|^6.0",
+ "symfony/event-dispatcher": "^4.4|^5.0|^6.0",
+ "symfony/dependency-injection": "^4.4|^5.0|^6.0",
+ "symfony/lock": "^4.4|^5.0|^6.0",
+ "symfony/process": "^4.4|^5.0|^6.0",
+ "symfony/var-dumper": "^4.4|^5.0|^6.0",
"psr/log": "^1|^2"
},
"provide": {
@@ -42,10 +44,11 @@
},
"conflict": {
"psr/log": ">=3",
- "symfony/dependency-injection": "<3.4",
- "symfony/event-dispatcher": "<4.3|>=5",
+ "symfony/dependency-injection": "<4.4",
+ "symfony/dotenv": "<5.1",
+ "symfony/event-dispatcher": "<4.4",
"symfony/lock": "<4.4",
- "symfony/process": "<3.3"
+ "symfony/process": "<4.4"
},
"autoload": {
"psr-4": { "Symfony\\Component\\Console\\": "" },
diff --git a/vendor/symfony/event-dispatcher-contracts/CHANGELOG.md b/vendor/symfony/event-dispatcher-contracts/CHANGELOG.md
new file mode 100644
index 000000000..7932e2613
--- /dev/null
+++ b/vendor/symfony/event-dispatcher-contracts/CHANGELOG.md
@@ -0,0 +1,5 @@
+CHANGELOG
+=========
+
+The changelog is maintained for all Symfony contracts at the following URL:
+https://github.com/symfony/contracts/blob/main/CHANGELOG.md
diff --git a/vendor/symfony/event-dispatcher-contracts/Event.php b/vendor/symfony/event-dispatcher-contracts/Event.php
index 84f60f3ed..46dcb2ba0 100644
--- a/vendor/symfony/event-dispatcher-contracts/Event.php
+++ b/vendor/symfony/event-dispatcher-contracts/Event.php
@@ -13,84 +13,42 @@ namespace Symfony\Contracts\EventDispatcher;
use Psr\EventDispatcher\StoppableEventInterface;
-if (interface_exists(StoppableEventInterface::class)) {
+/**
+ * Event is the base class for classes containing event data.
+ *
+ * This class contains no event data. It is used by events that do not pass
+ * state information to an event handler when an event is raised.
+ *
+ * You can call the method stopPropagation() to abort the execution of
+ * further listeners in your event listener.
+ *
+ * @author Guilherme Blanco
+ * @author Jonathan Wage
+ * @author Roman Borschel
+ * @author Bernhard Schussek
+ * @author Nicolas Grekas
+ */
+class Event implements StoppableEventInterface
+{
+ private $propagationStopped = false;
+
/**
- * Event is the base class for classes containing event data.
- *
- * This class contains no event data. It is used by events that do not pass
- * state information to an event handler when an event is raised.
- *
- * You can call the method stopPropagation() to abort the execution of
- * further listeners in your event listener.
- *
- * @author Guilherme Blanco
- * @author Jonathan Wage
- * @author Roman Borschel
- * @author Bernhard Schussek
- * @author Nicolas Grekas
+ * {@inheritdoc}
*/
- class Event implements StoppableEventInterface
+ public function isPropagationStopped(): bool
{
- private $propagationStopped = false;
-
- /**
- * Returns whether further event listeners should be triggered.
- */
- public function isPropagationStopped(): bool
- {
- return $this->propagationStopped;
- }
-
- /**
- * Stops the propagation of the event to further event listeners.
- *
- * If multiple event listeners are connected to the same event, no
- * further event listener will be triggered once any trigger calls
- * stopPropagation().
- */
- public function stopPropagation(): void
- {
- $this->propagationStopped = true;
- }
+ return $this->propagationStopped;
}
-} else {
+
/**
- * Event is the base class for classes containing event data.
+ * Stops the propagation of the event to further event listeners.
*
- * This class contains no event data. It is used by events that do not pass
- * state information to an event handler when an event is raised.
- *
- * You can call the method stopPropagation() to abort the execution of
- * further listeners in your event listener.
- *
- * @author Guilherme Blanco
- * @author Jonathan Wage
- * @author Roman Borschel
- * @author Bernhard Schussek
- * @author Nicolas Grekas
+ * If multiple event listeners are connected to the same event, no
+ * further event listener will be triggered once any trigger calls
+ * stopPropagation().
*/
- class Event
+ public function stopPropagation(): void
{
- private $propagationStopped = false;
-
- /**
- * Returns whether further event listeners should be triggered.
- */
- public function isPropagationStopped(): bool
- {
- return $this->propagationStopped;
- }
-
- /**
- * Stops the propagation of the event to further event listeners.
- *
- * If multiple event listeners are connected to the same event, no
- * further event listener will be triggered once any trigger calls
- * stopPropagation().
- */
- public function stopPropagation(): void
- {
- $this->propagationStopped = true;
- }
+ $this->propagationStopped = true;
}
}
diff --git a/vendor/symfony/event-dispatcher-contracts/EventDispatcherInterface.php b/vendor/symfony/event-dispatcher-contracts/EventDispatcherInterface.php
index 2d470af92..351dc5131 100644
--- a/vendor/symfony/event-dispatcher-contracts/EventDispatcherInterface.php
+++ b/vendor/symfony/event-dispatcher-contracts/EventDispatcherInterface.php
@@ -13,46 +13,19 @@ namespace Symfony\Contracts\EventDispatcher;
use Psr\EventDispatcher\EventDispatcherInterface as PsrEventDispatcherInterface;
-if (interface_exists(PsrEventDispatcherInterface::class)) {
+/**
+ * Allows providing hooks on domain-specific lifecycles by dispatching events.
+ */
+interface EventDispatcherInterface extends PsrEventDispatcherInterface
+{
/**
- * Allows providing hooks on domain-specific lifecycles by dispatching events.
+ * Dispatches an event to all registered listeners.
+ *
+ * @param object $event The event to pass to the event handlers/listeners
+ * @param string|null $eventName The name of the event to dispatch. If not supplied,
+ * the class of $event should be used instead.
+ *
+ * @return object The passed $event MUST be returned
*/
- interface EventDispatcherInterface extends PsrEventDispatcherInterface
- {
- /**
- * Dispatches an event to all registered listeners.
- *
- * For BC with Symfony 4, the $eventName argument is not declared explicitly on the
- * signature of the method. Implementations that are not bound by this BC constraint
- * MUST declare it explicitly, as allowed by PHP.
- *
- * @param object $event The event to pass to the event handlers/listeners
- * @param string|null $eventName The name of the event to dispatch. If not supplied,
- * the class of $event should be used instead.
- *
- * @return object The passed $event MUST be returned
- */
- public function dispatch($event/*, string $eventName = null*/);
- }
-} else {
- /**
- * Allows providing hooks on domain-specific lifecycles by dispatching events.
- */
- interface EventDispatcherInterface
- {
- /**
- * Dispatches an event to all registered listeners.
- *
- * For BC with Symfony 4, the $eventName argument is not declared explicitly on the
- * signature of the method. Implementations that are not bound by this BC constraint
- * MUST declare it explicitly, as allowed by PHP.
- *
- * @param object $event The event to pass to the event handlers/listeners
- * @param string|null $eventName The name of the event to dispatch. If not supplied,
- * the class of $event should be used instead.
- *
- * @return object The passed $event MUST be returned
- */
- public function dispatch($event/*, string $eventName = null*/);
- }
+ public function dispatch(object $event, string $eventName = null): object;
}
diff --git a/vendor/symfony/event-dispatcher-contracts/composer.json b/vendor/symfony/event-dispatcher-contracts/composer.json
index 9d4bd7bea..660df81a0 100644
--- a/vendor/symfony/event-dispatcher-contracts/composer.json
+++ b/vendor/symfony/event-dispatcher-contracts/composer.json
@@ -16,10 +16,10 @@
}
],
"require": {
- "php": ">=7.1.3"
+ "php": ">=7.2.5",
+ "psr/event-dispatcher": "^1"
},
"suggest": {
- "psr/event-dispatcher": "",
"symfony/event-dispatcher-implementation": ""
},
"autoload": {
@@ -28,7 +28,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
- "dev-main": "1.1-dev"
+ "dev-main": "2.5-dev"
},
"thanks": {
"name": "symfony/contracts",
diff --git a/vendor/symfony/event-dispatcher/Attribute/AsEventListener.php b/vendor/symfony/event-dispatcher/Attribute/AsEventListener.php
new file mode 100644
index 000000000..bb931b82d
--- /dev/null
+++ b/vendor/symfony/event-dispatcher/Attribute/AsEventListener.php
@@ -0,0 +1,29 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\EventDispatcher\Attribute;
+
+/**
+ * Service tag to autoconfigure event listeners.
+ *
+ * @author Alexander M. Turek
+ */
+#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
+class AsEventListener
+{
+ public function __construct(
+ public ?string $event = null,
+ public ?string $method = null,
+ public int $priority = 0,
+ public ?string $dispatcher = null,
+ ) {
+ }
+}
diff --git a/vendor/symfony/event-dispatcher/CHANGELOG.md b/vendor/symfony/event-dispatcher/CHANGELOG.md
index 4a3ea066e..0f9859895 100644
--- a/vendor/symfony/event-dispatcher/CHANGELOG.md
+++ b/vendor/symfony/event-dispatcher/CHANGELOG.md
@@ -1,6 +1,30 @@
CHANGELOG
=========
+5.4
+---
+
+ * Allow `#[AsEventListener]` attribute on methods
+
+5.3
+---
+
+ * Add `#[AsEventListener]` attribute for declaring listeners on PHP 8
+
+5.1.0
+-----
+
+ * The `LegacyEventDispatcherProxy` class has been deprecated.
+ * Added an optional `dispatcher` attribute to the listener and subscriber tags in `RegisterListenerPass`.
+
+5.0.0
+-----
+
+ * The signature of the `EventDispatcherInterface::dispatch()` method has been changed to `dispatch($event, string $eventName = null): object`.
+ * The `Event` class has been removed in favor of `Symfony\Contracts\EventDispatcher\Event`.
+ * The `TraceableEventDispatcherInterface` has been removed.
+ * The `WrappedListener` class is now final.
+
4.4.0
-----
diff --git a/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php b/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php
index e79d1a8e3..acfbf619c 100644
--- a/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php
+++ b/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php
@@ -13,15 +13,12 @@ namespace Symfony\Component\EventDispatcher\Debug;
use Psr\EventDispatcher\StoppableEventInterface;
use Psr\Log\LoggerInterface;
-use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy;
-use Symfony\Component\EventDispatcher\LegacyEventProxy;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Stopwatch\Stopwatch;
-use Symfony\Contracts\EventDispatcher\Event as ContractsEvent;
+use Symfony\Contracts\Service\ResetInterface;
/**
* Collects some data about event listeners.
@@ -30,11 +27,14 @@ use Symfony\Contracts\EventDispatcher\Event as ContractsEvent;
*
* @author Fabien Potencier
*/
-class TraceableEventDispatcher implements TraceableEventDispatcherInterface
+class TraceableEventDispatcher implements EventDispatcherInterface, ResetInterface
{
protected $logger;
protected $stopwatch;
+ /**
+ * @var \SplObjectStorage
+ */
private $callStack;
private $dispatcher;
private $wrappedListeners;
@@ -44,7 +44,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
public function __construct(EventDispatcherInterface $dispatcher, Stopwatch $stopwatch, LoggerInterface $logger = null, RequestStack $requestStack = null)
{
- $this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher);
+ $this->dispatcher = $dispatcher;
$this->stopwatch = $stopwatch;
$this->logger = $logger;
$this->wrappedListeners = [];
@@ -55,7 +55,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
/**
* {@inheritdoc}
*/
- public function addListener($eventName, $listener, $priority = 0)
+ public function addListener(string $eventName, $listener, int $priority = 0)
{
$this->dispatcher->addListener($eventName, $listener, $priority);
}
@@ -71,11 +71,11 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
/**
* {@inheritdoc}
*/
- public function removeListener($eventName, $listener)
+ public function removeListener(string $eventName, $listener)
{
if (isset($this->wrappedListeners[$eventName])) {
foreach ($this->wrappedListeners[$eventName] as $index => $wrappedListener) {
- if ($wrappedListener->getWrappedListener() === $listener) {
+ if ($wrappedListener->getWrappedListener() === $listener || ($listener instanceof \Closure && $wrappedListener->getWrappedListener() == $listener)) {
$listener = $wrappedListener;
unset($this->wrappedListeners[$eventName][$index]);
break;
@@ -97,7 +97,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
/**
* {@inheritdoc}
*/
- public function getListeners($eventName = null)
+ public function getListeners(string $eventName = null)
{
return $this->dispatcher->getListeners($eventName);
}
@@ -105,13 +105,13 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
/**
* {@inheritdoc}
*/
- public function getListenerPriority($eventName, $listener)
+ public function getListenerPriority(string $eventName, $listener)
{
// we might have wrapped listeners for the event (if called while dispatching)
// in that case get the priority by wrapper
if (isset($this->wrappedListeners[$eventName])) {
- foreach ($this->wrappedListeners[$eventName] as $index => $wrappedListener) {
- if ($wrappedListener->getWrappedListener() === $listener) {
+ foreach ($this->wrappedListeners[$eventName] as $wrappedListener) {
+ if ($wrappedListener->getWrappedListener() === $listener || ($listener instanceof \Closure && $wrappedListener->getWrappedListener() == $listener)) {
return $this->dispatcher->getListenerPriority($eventName, $wrappedListener);
}
}
@@ -123,39 +123,25 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
/**
* {@inheritdoc}
*/
- public function hasListeners($eventName = null)
+ public function hasListeners(string $eventName = null)
{
return $this->dispatcher->hasListeners($eventName);
}
/**
* {@inheritdoc}
- *
- * @param string|null $eventName
*/
- public function dispatch($event/*, string $eventName = null*/)
+ public function dispatch(object $event, string $eventName = null): object
{
+ $eventName = $eventName ?? \get_class($event);
+
if (null === $this->callStack) {
$this->callStack = new \SplObjectStorage();
}
$currentRequestHash = $this->currentRequestHash = $this->requestStack && ($request = $this->requestStack->getCurrentRequest()) ? spl_object_hash($request) : '';
- $eventName = 1 < \func_num_args() ? func_get_arg(1) : null;
- if (\is_object($event)) {
- $eventName = $eventName ?? \get_class($event);
- } else {
- @trigger_error(sprintf('Calling the "%s::dispatch()" method with the event name as first argument is deprecated since Symfony 4.3, pass it second and provide the event object first instead.', EventDispatcherInterface::class), \E_USER_DEPRECATED);
- $swap = $event;
- $event = $eventName ?? new Event();
- $eventName = $swap;
-
- if (!$event instanceof Event) {
- throw new \TypeError(sprintf('Argument 1 passed to "%s::dispatch()" must be an instance of "%s", "%s" given.', EventDispatcherInterface::class, Event::class, \is_object($event) ? \get_class($event) : \gettype($event)));
- }
- }
-
- if (null !== $this->logger && ($event instanceof Event || $event instanceof ContractsEvent || $event instanceof StoppableEventInterface) && $event->isPropagationStopped()) {
+ if (null !== $this->logger && $event instanceof StoppableEventInterface && $event->isPropagationStopped()) {
$this->logger->debug(sprintf('The "%s" event is already stopped. No listeners have been called.', $eventName));
}
@@ -183,17 +169,15 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
}
/**
- * {@inheritdoc}
- *
- * @param Request|null $request The request to get listeners for
+ * @return array
*/
- public function getCalledListeners(/* Request $request = null */)
+ public function getCalledListeners(Request $request = null)
{
if (null === $this->callStack) {
return [];
}
- $hash = 1 <= \func_num_args() && null !== ($request = func_get_arg(0)) ? spl_object_hash($request) : null;
+ $hash = $request ? spl_object_hash($request) : null;
$called = [];
foreach ($this->callStack as $listener) {
[$eventName, $requestHash] = $this->callStack->getInfo();
@@ -206,11 +190,9 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
}
/**
- * {@inheritdoc}
- *
- * @param Request|null $request The request to get listeners for
+ * @return array
*/
- public function getNotCalledListeners(/* Request $request = null */)
+ public function getNotCalledListeners(Request $request = null)
{
try {
$allListeners = $this->getListeners();
@@ -223,7 +205,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
return [];
}
- $hash = 1 <= \func_num_args() && null !== ($request = func_get_arg(0)) ? spl_object_hash($request) : null;
+ $hash = $request ? spl_object_hash($request) : null;
$calledListeners = [];
if (null !== $this->callStack) {
@@ -253,12 +235,9 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
return $notCalled;
}
- /**
- * @param Request|null $request The request to get orphaned events for
- */
- public function getOrphanedEvents(/* Request $request = null */): array
+ public function getOrphanedEvents(Request $request = null): array
{
- if (1 <= \func_num_args() && null !== $request = func_get_arg(0)) {
+ if ($request) {
return $this->orphanedEvents[spl_object_hash($request)] ?? [];
}
@@ -284,46 +263,26 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
*
* @return mixed
*/
- public function __call($method, $arguments)
+ public function __call(string $method, array $arguments)
{
return $this->dispatcher->{$method}(...$arguments);
}
/**
* Called before dispatching the event.
- *
- * @param object $event
*/
- protected function beforeDispatch(string $eventName, $event)
+ protected function beforeDispatch(string $eventName, object $event)
{
- $this->preDispatch($eventName, $event instanceof Event ? $event : new LegacyEventProxy($event));
}
/**
* Called after dispatching the event.
- *
- * @param object $event
*/
- protected function afterDispatch(string $eventName, $event)
- {
- $this->postDispatch($eventName, $event instanceof Event ? $event : new LegacyEventProxy($event));
- }
-
- /**
- * @deprecated since Symfony 4.3, will be removed in 5.0, use beforeDispatch instead
- */
- protected function preDispatch($eventName, Event $event)
+ protected function afterDispatch(string $eventName, object $event)
{
}
- /**
- * @deprecated since Symfony 4.3, will be removed in 5.0, use afterDispatch instead
- */
- protected function postDispatch($eventName, Event $event)
- {
- }
-
- private function preProcess(string $eventName)
+ private function preProcess(string $eventName): void
{
if (!$this->dispatcher->hasListeners($eventName)) {
$this->orphanedEvents[$this->currentRequestHash][] = $eventName;
@@ -341,7 +300,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
}
}
- private function postProcess(string $eventName)
+ private function postProcess(string $eventName): void
{
unset($this->wrappedListeners[$eventName]);
$skipped = false;
diff --git a/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.php b/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.php
deleted file mode 100644
index 4fedb9a41..000000000
--- a/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.php
+++ /dev/null
@@ -1,42 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\EventDispatcher\Debug;
-
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
-use Symfony\Component\HttpFoundation\Request;
-use Symfony\Contracts\Service\ResetInterface;
-
-/**
- * @deprecated since Symfony 4.1
- *
- * @author Fabien Potencier
- */
-interface TraceableEventDispatcherInterface extends EventDispatcherInterface, ResetInterface
-{
- /**
- * Gets the called listeners.
- *
- * @param Request|null $request The request to get listeners for
- *
- * @return array An array of called listeners
- */
- public function getCalledListeners(/* Request $request = null */);
-
- /**
- * Gets the not called listeners.
- *
- * @param Request|null $request The request to get listeners for
- *
- * @return array An array of not called listeners
- */
- public function getNotCalledListeners(/* Request $request = null */);
-}
diff --git a/vendor/symfony/event-dispatcher/Debug/WrappedListener.php b/vendor/symfony/event-dispatcher/Debug/WrappedListener.php
index 9b910e667..86d3854b2 100644
--- a/vendor/symfony/event-dispatcher/Debug/WrappedListener.php
+++ b/vendor/symfony/event-dispatcher/Debug/WrappedListener.php
@@ -12,19 +12,14 @@
namespace Symfony\Component\EventDispatcher\Debug;
use Psr\EventDispatcher\StoppableEventInterface;
-use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
-use Symfony\Component\EventDispatcher\LegacyEventProxy;
use Symfony\Component\Stopwatch\Stopwatch;
use Symfony\Component\VarDumper\Caster\ClassStub;
-use Symfony\Contracts\EventDispatcher\Event as ContractsEvent;
/**
* @author Fabien Potencier
- *
- * @final since Symfony 4.3: the "Event" type-hint on __invoke() will be replaced by "object" in 5.0
*/
-class WrappedListener
+final class WrappedListener
{
private $listener;
private $optimizedListener;
@@ -48,13 +43,13 @@ class WrappedListener
$this->stoppedPropagation = false;
if (\is_array($listener)) {
- $this->name = \is_object($listener[0]) ? \get_class($listener[0]) : $listener[0];
+ $this->name = \is_object($listener[0]) ? get_debug_type($listener[0]) : $listener[0];
$this->pretty = $this->name.'::'.$listener[1];
} elseif ($listener instanceof \Closure) {
$r = new \ReflectionFunction($listener);
if (str_contains($r->name, '{closure}')) {
$this->pretty = $this->name = 'closure';
- } elseif ($class = $r->getClosureScopeClass()) {
+ } elseif ($class = \PHP_VERSION_ID >= 80111 ? $r->getClosureCalledClass() : $r->getClosureScopeClass()) {
$this->name = $class->name;
$this->pretty = $this->name.'::'.$r->name;
} else {
@@ -63,7 +58,7 @@ class WrappedListener
} elseif (\is_string($listener)) {
$this->pretty = $this->name = $listener;
} else {
- $this->name = \get_class($listener);
+ $this->name = get_debug_type($listener);
$this->pretty = $this->name.'::__invoke';
}
@@ -81,22 +76,22 @@ class WrappedListener
return $this->listener;
}
- public function wasCalled()
+ public function wasCalled(): bool
{
return $this->called;
}
- public function stoppedPropagation()
+ public function stoppedPropagation(): bool
{
return $this->stoppedPropagation;
}
- public function getPretty()
+ public function getPretty(): string
{
return $this->pretty;
}
- public function getInfo($eventName)
+ public function getInfo(string $eventName): array
{
if (null === $this->stub) {
$this->stub = self::$hasClassStub ? new ClassStub($this->pretty.'()', $this->listener) : $this->pretty.'()';
@@ -110,12 +105,8 @@ class WrappedListener
];
}
- public function __invoke(Event $event, $eventName, EventDispatcherInterface $dispatcher)
+ public function __invoke(object $event, string $eventName, EventDispatcherInterface $dispatcher): void
{
- if ($event instanceof LegacyEventProxy) {
- $event = $event->getEvent();
- }
-
$dispatcher = $this->dispatcher ?: $dispatcher;
$this->called = true;
@@ -129,7 +120,7 @@ class WrappedListener
$e->stop();
}
- if (($event instanceof Event || $event instanceof ContractsEvent || $event instanceof StoppableEventInterface) && $event->isPropagationStopped()) {
+ if ($event instanceof StoppableEventInterface && $event->isPropagationStopped()) {
$this->stoppedPropagation = true;
}
}
diff --git a/vendor/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php b/vendor/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php
index c4ea50f78..6e7292b4a 100644
--- a/vendor/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php
+++ b/vendor/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php
@@ -26,6 +26,10 @@ class AddEventAliasesPass implements CompilerPassInterface
public function __construct(array $eventAliases, string $eventAliasesParameter = 'event_dispatcher.event_aliases')
{
+ if (1 < \func_num_args()) {
+ trigger_deprecation('symfony/event-dispatcher', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
+ }
+
$this->eventAliases = $eventAliases;
$this->eventAliasesParameter = $eventAliasesParameter;
}
diff --git a/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php b/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php
index 1c4e12ec8..8eabe7d74 100644
--- a/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php
+++ b/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php
@@ -16,7 +16,6 @@ use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Reference;
-use Symfony\Component\EventDispatcher\Event as LegacyEvent;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Contracts\EventDispatcher\Event;
@@ -32,20 +31,48 @@ class RegisterListenersPass implements CompilerPassInterface
protected $eventAliasesParameter;
private $hotPathEvents = [];
- private $hotPathTagName;
+ private $hotPathTagName = 'container.hot_path';
+ private $noPreloadEvents = [];
+ private $noPreloadTagName = 'container.no_preload';
public function __construct(string $dispatcherService = 'event_dispatcher', string $listenerTag = 'kernel.event_listener', string $subscriberTag = 'kernel.event_subscriber', string $eventAliasesParameter = 'event_dispatcher.event_aliases')
{
+ if (0 < \func_num_args()) {
+ trigger_deprecation('symfony/event-dispatcher', '5.3', 'Configuring "%s" is deprecated.', __CLASS__);
+ }
+
$this->dispatcherService = $dispatcherService;
$this->listenerTag = $listenerTag;
$this->subscriberTag = $subscriberTag;
$this->eventAliasesParameter = $eventAliasesParameter;
}
- public function setHotPathEvents(array $hotPathEvents, $tagName = 'container.hot_path')
+ /**
+ * @return $this
+ */
+ public function setHotPathEvents(array $hotPathEvents)
{
$this->hotPathEvents = array_flip($hotPathEvents);
- $this->hotPathTagName = $tagName;
+
+ if (1 < \func_num_args()) {
+ trigger_deprecation('symfony/event-dispatcher', '5.4', 'Configuring "$tagName" in "%s" is deprecated.', __METHOD__);
+ $this->hotPathTagName = func_get_arg(1);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return $this
+ */
+ public function setNoPreloadEvents(array $noPreloadEvents): self
+ {
+ $this->noPreloadEvents = array_flip($noPreloadEvents);
+
+ if (1 < \func_num_args()) {
+ trigger_deprecation('symfony/event-dispatcher', '5.4', 'Configuring "$tagName" in "%s" is deprecated.', __METHOD__);
+ $this->noPreloadTagName = func_get_arg(1);
+ }
return $this;
}
@@ -62,9 +89,11 @@ class RegisterListenersPass implements CompilerPassInterface
$aliases = $container->getParameter($this->eventAliasesParameter);
}
- $definition = $container->findDefinition($this->dispatcherService);
+ $globalDispatcherDefinition = $container->findDefinition($this->dispatcherService);
foreach ($container->findTaggedServiceIds($this->listenerTag, true) as $id => $events) {
+ $noPreload = 0;
+
foreach ($events as $event) {
$priority = $event['priority'] ?? 0;
@@ -91,17 +120,28 @@ class RegisterListenersPass implements CompilerPassInterface
}
}
- $definition->addMethodCall('addListener', [$event['event'], [new ServiceClosureArgument(new Reference($id)), $event['method']], $priority]);
+ $dispatcherDefinition = $globalDispatcherDefinition;
+ if (isset($event['dispatcher'])) {
+ $dispatcherDefinition = $container->getDefinition($event['dispatcher']);
+ }
+
+ $dispatcherDefinition->addMethodCall('addListener', [$event['event'], [new ServiceClosureArgument(new Reference($id)), $event['method']], $priority]);
if (isset($this->hotPathEvents[$event['event']])) {
$container->getDefinition($id)->addTag($this->hotPathTagName);
+ } elseif (isset($this->noPreloadEvents[$event['event']])) {
+ ++$noPreload;
}
}
+
+ if ($noPreload && \count($events) === $noPreload) {
+ $container->getDefinition($id)->addTag($this->noPreloadTagName);
+ }
}
$extractingDispatcher = new ExtractingEventDispatcher();
- foreach ($container->findTaggedServiceIds($this->subscriberTag, true) as $id => $attributes) {
+ foreach ($container->findTaggedServiceIds($this->subscriberTag, true) as $id => $tags) {
$def = $container->getDefinition($id);
// We must assume that the class value has been correctly filled, even if the service is created by a factory
@@ -115,17 +155,38 @@ class RegisterListenersPass implements CompilerPassInterface
}
$class = $r->name;
+ $dispatcherDefinitions = [];
+ foreach ($tags as $attributes) {
+ if (!isset($attributes['dispatcher']) || isset($dispatcherDefinitions[$attributes['dispatcher']])) {
+ continue;
+ }
+
+ $dispatcherDefinitions[$attributes['dispatcher']] = $container->getDefinition($attributes['dispatcher']);
+ }
+
+ if (!$dispatcherDefinitions) {
+ $dispatcherDefinitions = [$globalDispatcherDefinition];
+ }
+
+ $noPreload = 0;
ExtractingEventDispatcher::$aliases = $aliases;
ExtractingEventDispatcher::$subscriber = $class;
$extractingDispatcher->addSubscriber($extractingDispatcher);
foreach ($extractingDispatcher->listeners as $args) {
$args[1] = [new ServiceClosureArgument(new Reference($id)), $args[1]];
- $definition->addMethodCall('addListener', $args);
+ foreach ($dispatcherDefinitions as $dispatcherDefinition) {
+ $dispatcherDefinition->addMethodCall('addListener', $args);
+ }
if (isset($this->hotPathEvents[$args[0]])) {
$container->getDefinition($id)->addTag($this->hotPathTagName);
+ } elseif (isset($this->noPreloadEvents[$args[0]])) {
+ ++$noPreload;
}
}
+ if ($noPreload && \count($extractingDispatcher->listeners) === $noPreload) {
+ $container->getDefinition($id)->addTag($this->noPreloadTagName);
+ }
$extractingDispatcher->listeners = [];
ExtractingEventDispatcher::$aliases = [];
}
@@ -141,7 +202,6 @@ class RegisterListenersPass implements CompilerPassInterface
|| !($type = $m->getParameters()[0]->getType()) instanceof \ReflectionNamedType
|| $type->isBuiltin()
|| Event::class === ($name = $type->getName())
- || LegacyEvent::class === $name
) {
throw new InvalidArgumentException(sprintf('Service "%s" must define the "event" attribute on "%s" tags.', $id, $this->listenerTag));
}
@@ -160,7 +220,7 @@ class ExtractingEventDispatcher extends EventDispatcher implements EventSubscrib
public static $aliases = [];
public static $subscriber;
- public function addListener($eventName, $listener, $priority = 0)
+ public function addListener(string $eventName, $listener, int $priority = 0)
{
$this->listeners[] = [$eventName, $listener[1], $priority];
}
diff --git a/vendor/symfony/event-dispatcher/Event.php b/vendor/symfony/event-dispatcher/Event.php
deleted file mode 100644
index 307c4be5d..000000000
--- a/vendor/symfony/event-dispatcher/Event.php
+++ /dev/null
@@ -1,38 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\EventDispatcher;
-
-/**
- * @deprecated since Symfony 4.3, use "Symfony\Contracts\EventDispatcher\Event" instead
- */
-class Event
-{
- private $propagationStopped = false;
-
- /**
- * @return bool Whether propagation was already stopped for this event
- *
- * @deprecated since Symfony 4.3, use "Symfony\Contracts\EventDispatcher\Event" instead
- */
- public function isPropagationStopped()
- {
- return $this->propagationStopped;
- }
-
- /**
- * @deprecated since Symfony 4.3, use "Symfony\Contracts\EventDispatcher\Event" instead
- */
- public function stopPropagation()
- {
- $this->propagationStopped = true;
- }
-}
diff --git a/vendor/symfony/event-dispatcher/EventDispatcher.php b/vendor/symfony/event-dispatcher/EventDispatcher.php
index 8b6222718..8fe8fb5c2 100644
--- a/vendor/symfony/event-dispatcher/EventDispatcher.php
+++ b/vendor/symfony/event-dispatcher/EventDispatcher.php
@@ -13,7 +13,6 @@ namespace Symfony\Component\EventDispatcher;
use Psr\EventDispatcher\StoppableEventInterface;
use Symfony\Component\EventDispatcher\Debug\WrappedListener;
-use Symfony\Contracts\EventDispatcher\Event as ContractsEvent;
/**
* The EventDispatcherInterface is the central point of Symfony's event listener system.
@@ -45,25 +44,12 @@ class EventDispatcher implements EventDispatcherInterface
/**
* {@inheritdoc}
- *
- * @param string|null $eventName
*/
- public function dispatch($event/*, string $eventName = null*/)
+ public function dispatch(object $event, string $eventName = null): object
{
- $eventName = 1 < \func_num_args() ? func_get_arg(1) : null;
+ $eventName = $eventName ?? \get_class($event);
- if (\is_object($event)) {
- $eventName = $eventName ?? \get_class($event);
- } elseif (\is_string($event) && (null === $eventName || $eventName instanceof ContractsEvent || $eventName instanceof Event)) {
- @trigger_error(sprintf('Calling the "%s::dispatch()" method with the event name as the first argument is deprecated since Symfony 4.3, pass it as the second argument and provide the event object as the first argument instead.', EventDispatcherInterface::class), \E_USER_DEPRECATED);
- $swap = $event;
- $event = $eventName ?? new Event();
- $eventName = $swap;
- } else {
- throw new \TypeError(sprintf('Argument 1 passed to "%s::dispatch()" must be an object, "%s" given.', EventDispatcherInterface::class, \is_object($event) ? \get_class($event) : \gettype($event)));
- }
-
- if (null !== $this->optimized && null !== $eventName) {
+ if (null !== $this->optimized) {
$listeners = $this->optimized[$eventName] ?? (empty($this->listeners[$eventName]) ? [] : $this->optimizeListeners($eventName));
} else {
$listeners = $this->getListeners($eventName);
@@ -79,7 +65,7 @@ class EventDispatcher implements EventDispatcherInterface
/**
* {@inheritdoc}
*/
- public function getListeners($eventName = null)
+ public function getListeners(string $eventName = null)
{
if (null !== $eventName) {
if (empty($this->listeners[$eventName])) {
@@ -105,7 +91,7 @@ class EventDispatcher implements EventDispatcherInterface
/**
* {@inheritdoc}
*/
- public function getListenerPriority($eventName, $listener)
+ public function getListenerPriority(string $eventName, $listener)
{
if (empty($this->listeners[$eventName])) {
return null;
@@ -122,7 +108,7 @@ class EventDispatcher implements EventDispatcherInterface
$v[0] = $v[0]();
$v[1] = $v[1] ?? '__invoke';
}
- if ($v === $listener) {
+ if ($v === $listener || ($listener instanceof \Closure && $v == $listener)) {
return $priority;
}
}
@@ -134,7 +120,7 @@ class EventDispatcher implements EventDispatcherInterface
/**
* {@inheritdoc}
*/
- public function hasListeners($eventName = null)
+ public function hasListeners(string $eventName = null)
{
if (null !== $eventName) {
return !empty($this->listeners[$eventName]);
@@ -152,7 +138,7 @@ class EventDispatcher implements EventDispatcherInterface
/**
* {@inheritdoc}
*/
- public function addListener($eventName, $listener, $priority = 0)
+ public function addListener(string $eventName, $listener, int $priority = 0)
{
$this->listeners[$eventName][$priority][] = $listener;
unset($this->sorted[$eventName], $this->optimized[$eventName]);
@@ -161,7 +147,7 @@ class EventDispatcher implements EventDispatcherInterface
/**
* {@inheritdoc}
*/
- public function removeListener($eventName, $listener)
+ public function removeListener(string $eventName, $listener)
{
if (empty($this->listeners[$eventName])) {
return;
@@ -178,7 +164,7 @@ class EventDispatcher implements EventDispatcherInterface
$v[0] = $v[0]();
$v[1] = $v[1] ?? '__invoke';
}
- if ($v === $listener) {
+ if ($v === $listener || ($listener instanceof \Closure && $v == $listener)) {
unset($listeners[$k], $this->sorted[$eventName], $this->optimized[$eventName]);
}
}
@@ -233,34 +219,14 @@ class EventDispatcher implements EventDispatcherInterface
* @param string $eventName The name of the event to dispatch
* @param object $event The event object to pass to the event handlers/listeners
*/
- protected function callListeners(iterable $listeners, string $eventName, $event)
+ protected function callListeners(iterable $listeners, string $eventName, object $event)
{
- if ($event instanceof Event) {
- $this->doDispatch($listeners, $eventName, $event);
-
- return;
- }
-
- $stoppable = $event instanceof ContractsEvent || $event instanceof StoppableEventInterface;
+ $stoppable = $event instanceof StoppableEventInterface;
foreach ($listeners as $listener) {
if ($stoppable && $event->isPropagationStopped()) {
break;
}
- // @deprecated: the ternary operator is part of a BC layer and should be removed in 5.0
- $listener($listener instanceof WrappedListener ? new LegacyEventProxy($event) : $event, $eventName, $this);
- }
- }
-
- /**
- * @deprecated since Symfony 4.3, use callListeners() instead
- */
- protected function doDispatch($listeners, $eventName, Event $event)
- {
- foreach ($listeners as $listener) {
- if ($event->isPropagationStopped()) {
- break;
- }
$listener($event, $eventName, $this);
}
}
diff --git a/vendor/symfony/event-dispatcher/EventDispatcherInterface.php b/vendor/symfony/event-dispatcher/EventDispatcherInterface.php
index ceaa62aeb..cc324e1c6 100644
--- a/vendor/symfony/event-dispatcher/EventDispatcherInterface.php
+++ b/vendor/symfony/event-dispatcher/EventDispatcherInterface.php
@@ -25,12 +25,10 @@ interface EventDispatcherInterface extends ContractsEventDispatcherInterface
/**
* Adds an event listener that listens on the specified events.
*
- * @param string $eventName The event to listen on
- * @param callable $listener The listener
- * @param int $priority The higher this value, the earlier an event
- * listener will be triggered in the chain (defaults to 0)
+ * @param int $priority The higher this value, the earlier an event
+ * listener will be triggered in the chain (defaults to 0)
*/
- public function addListener($eventName, $listener, $priority = 0);
+ public function addListener(string $eventName, callable $listener, int $priority = 0);
/**
* Adds an event subscriber.
@@ -42,41 +40,31 @@ interface EventDispatcherInterface extends ContractsEventDispatcherInterface
/**
* Removes an event listener from the specified events.
- *
- * @param string $eventName The event to remove a listener from
- * @param callable $listener The listener to remove
*/
- public function removeListener($eventName, $listener);
+ public function removeListener(string $eventName, callable $listener);
public function removeSubscriber(EventSubscriberInterface $subscriber);
/**
* Gets the listeners of a specific event or all listeners sorted by descending priority.
*
- * @param string|null $eventName The name of the event
- *
- * @return array The event listeners for the specified event, or all event listeners by event name
+ * @return array
*/
- public function getListeners($eventName = null);
+ public function getListeners(string $eventName = null);
/**
* Gets the listener priority for a specific event.
*
* Returns null if the event or the listener does not exist.
*
- * @param string $eventName The name of the event
- * @param callable $listener The listener
- *
- * @return int|null The event listener priority
+ * @return int|null
*/
- public function getListenerPriority($eventName, $listener);
+ public function getListenerPriority(string $eventName, callable $listener);
/**
* Checks whether an event has any registered listeners.
*
- * @param string|null $eventName The name of the event
- *
- * @return bool true if the specified event has any listeners, false otherwise
+ * @return bool
*/
- public function hasListeners($eventName = null);
+ public function hasListeners(string $eventName = null);
}
diff --git a/vendor/symfony/event-dispatcher/EventSubscriberInterface.php b/vendor/symfony/event-dispatcher/EventSubscriberInterface.php
index a0fc96dfe..2085e428e 100644
--- a/vendor/symfony/event-dispatcher/EventSubscriberInterface.php
+++ b/vendor/symfony/event-dispatcher/EventSubscriberInterface.php
@@ -43,7 +43,7 @@ interface EventSubscriberInterface
* The code must not depend on runtime state as it will only be called at compile time.
* All logic depending on runtime state must be put into the individual methods handling the events.
*
- * @return array The event names to listen to
+ * @return array>
*/
public static function getSubscribedEvents();
}
diff --git a/vendor/symfony/event-dispatcher/GenericEvent.php b/vendor/symfony/event-dispatcher/GenericEvent.php
index 23333bc21..b32a301ae 100644
--- a/vendor/symfony/event-dispatcher/GenericEvent.php
+++ b/vendor/symfony/event-dispatcher/GenericEvent.php
@@ -11,12 +11,17 @@
namespace Symfony\Component\EventDispatcher;
+use Symfony\Contracts\EventDispatcher\Event;
+
/**
* Event encapsulation class.
*
* Encapsulates events thus decoupling the observer from the subject they encapsulate.
*
* @author Drak
+ *
+ * @implements \ArrayAccess
+ * @implements \IteratorAggregate
*/
class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate
{
@@ -38,7 +43,7 @@ class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate
/**
* Getter for subject property.
*
- * @return mixed The observer subject
+ * @return mixed
*/
public function getSubject()
{
@@ -48,13 +53,11 @@ class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate
/**
* Get argument by key.
*
- * @param string $key Key
- *
- * @return mixed Contents of array key
+ * @return mixed
*
* @throws \InvalidArgumentException if key is not found
*/
- public function getArgument($key)
+ public function getArgument(string $key)
{
if ($this->hasArgument($key)) {
return $this->arguments[$key];
@@ -66,12 +69,11 @@ class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate
/**
* Add argument to event.
*
- * @param string $key Argument name
- * @param mixed $value Value
+ * @param mixed $value Value
*
* @return $this
*/
- public function setArgument($key, $value)
+ public function setArgument(string $key, $value)
{
$this->arguments[$key] = $value;
@@ -91,8 +93,6 @@ class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate
/**
* Set args property.
*
- * @param array $args Arguments
- *
* @return $this
*/
public function setArguments(array $args = [])
@@ -105,11 +105,9 @@ class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate
/**
* Has argument.
*
- * @param string $key Key of arguments array
- *
* @return bool
*/
- public function hasArgument($key)
+ public function hasArgument(string $key)
{
return \array_key_exists($key, $this->arguments);
}
@@ -174,7 +172,7 @@ class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate
/**
* IteratorAggregate for iterating over the object like an array.
*
- * @return \ArrayIterator
+ * @return \ArrayIterator
*/
#[\ReturnTypeWillChange]
public function getIterator()
diff --git a/vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php b/vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php
index 75a7d7318..568d79c3a 100644
--- a/vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php
+++ b/vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php
@@ -22,32 +22,21 @@ class ImmutableEventDispatcher implements EventDispatcherInterface
public function __construct(EventDispatcherInterface $dispatcher)
{
- $this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher);
+ $this->dispatcher = $dispatcher;
}
/**
* {@inheritdoc}
- *
- * @param string|null $eventName
*/
- public function dispatch($event/*, string $eventName = null*/)
+ public function dispatch(object $event, string $eventName = null): object
{
- $eventName = 1 < \func_num_args() ? func_get_arg(1) : null;
-
- if (is_scalar($event)) {
- // deprecated
- $swap = $event;
- $event = $eventName ?? new Event();
- $eventName = $swap;
- }
-
return $this->dispatcher->dispatch($event, $eventName);
}
/**
* {@inheritdoc}
*/
- public function addListener($eventName, $listener, $priority = 0)
+ public function addListener(string $eventName, $listener, int $priority = 0)
{
throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
}
@@ -63,7 +52,7 @@ class ImmutableEventDispatcher implements EventDispatcherInterface
/**
* {@inheritdoc}
*/
- public function removeListener($eventName, $listener)
+ public function removeListener(string $eventName, $listener)
{
throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
}
@@ -79,7 +68,7 @@ class ImmutableEventDispatcher implements EventDispatcherInterface
/**
* {@inheritdoc}
*/
- public function getListeners($eventName = null)
+ public function getListeners(string $eventName = null)
{
return $this->dispatcher->getListeners($eventName);
}
@@ -87,7 +76,7 @@ class ImmutableEventDispatcher implements EventDispatcherInterface
/**
* {@inheritdoc}
*/
- public function getListenerPriority($eventName, $listener)
+ public function getListenerPriority(string $eventName, $listener)
{
return $this->dispatcher->getListenerPriority($eventName, $listener);
}
@@ -95,7 +84,7 @@ class ImmutableEventDispatcher implements EventDispatcherInterface
/**
* {@inheritdoc}
*/
- public function hasListeners($eventName = null)
+ public function hasListeners(string $eventName = null)
{
return $this->dispatcher->hasListeners($eventName);
}
diff --git a/vendor/symfony/event-dispatcher/LICENSE b/vendor/symfony/event-dispatcher/LICENSE
index 88bf75bb4..0138f8f07 100644
--- a/vendor/symfony/event-dispatcher/LICENSE
+++ b/vendor/symfony/event-dispatcher/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2004-2022 Fabien Potencier
+Copyright (c) 2004-present 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
diff --git a/vendor/symfony/event-dispatcher/LegacyEventDispatcherProxy.php b/vendor/symfony/event-dispatcher/LegacyEventDispatcherProxy.php
index 8ee6cba1b..6e17c8fcc 100644
--- a/vendor/symfony/event-dispatcher/LegacyEventDispatcherProxy.php
+++ b/vendor/symfony/event-dispatcher/LegacyEventDispatcherProxy.php
@@ -11,137 +11,21 @@
namespace Symfony\Component\EventDispatcher;
-use Psr\EventDispatcher\StoppableEventInterface;
-use Symfony\Contracts\EventDispatcher\Event as ContractsEvent;
-use Symfony\Contracts\EventDispatcher\EventDispatcherInterface as ContractsEventDispatcherInterface;
+use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
+
+trigger_deprecation('symfony/event-dispatcher', '5.1', '%s is deprecated, use the event dispatcher without the proxy.', LegacyEventDispatcherProxy::class);
/**
* A helper class to provide BC/FC with the legacy signature of EventDispatcherInterface::dispatch().
*
- * This class should be deprecated in Symfony 5.1
- *
* @author Nicolas Grekas
+ *
+ * @deprecated since Symfony 5.1
*/
-final class LegacyEventDispatcherProxy implements EventDispatcherInterface
+final class LegacyEventDispatcherProxy
{
- private $dispatcher;
-
- public static function decorate(?ContractsEventDispatcherInterface $dispatcher): ?ContractsEventDispatcherInterface
+ public static function decorate(?EventDispatcherInterface $dispatcher): ?EventDispatcherInterface
{
- if (null === $dispatcher) {
- return null;
- }
- $r = new \ReflectionMethod($dispatcher, 'dispatch');
- $param2 = $r->getParameters()[1] ?? null;
-
- if (!$param2 || !$param2->hasType() || $param2->getType()->isBuiltin()) {
- return $dispatcher;
- }
-
- @trigger_error(sprintf('The signature of the "%s::dispatch()" method should be updated to "dispatch($event, string $eventName = null)", not doing so is deprecated since Symfony 4.3.', $r->class), \E_USER_DEPRECATED);
-
- $self = new self();
- $self->dispatcher = $dispatcher;
-
- return $self;
- }
-
- /**
- * {@inheritdoc}
- *
- * @param string|null $eventName
- *
- * @return object
- */
- public function dispatch($event/*, string $eventName = null*/)
- {
- $eventName = 1 < \func_num_args() ? func_get_arg(1) : null;
-
- if (\is_object($event)) {
- $eventName = $eventName ?? \get_class($event);
- } elseif (\is_string($event) && (null === $eventName || $eventName instanceof ContractsEvent || $eventName instanceof Event)) {
- @trigger_error(sprintf('Calling the "%s::dispatch()" method with the event name as the first argument is deprecated since Symfony 4.3, pass it as the second argument and provide the event object as the first argument instead.', ContractsEventDispatcherInterface::class), \E_USER_DEPRECATED);
- $swap = $event;
- $event = $eventName ?? new Event();
- $eventName = $swap;
- } else {
- throw new \TypeError(sprintf('Argument 1 passed to "%s::dispatch()" must be an object, "%s" given.', ContractsEventDispatcherInterface::class, \is_object($event) ? \get_class($event) : \gettype($event)));
- }
-
- $listeners = $this->getListeners($eventName);
- $stoppable = $event instanceof Event || $event instanceof ContractsEvent || $event instanceof StoppableEventInterface;
-
- foreach ($listeners as $listener) {
- if ($stoppable && $event->isPropagationStopped()) {
- break;
- }
- $listener($event, $eventName, $this);
- }
-
- return $event;
- }
-
- /**
- * {@inheritdoc}
- */
- public function addListener($eventName, $listener, $priority = 0)
- {
- return $this->dispatcher->addListener($eventName, $listener, $priority);
- }
-
- /**
- * {@inheritdoc}
- */
- public function addSubscriber(EventSubscriberInterface $subscriber)
- {
- return $this->dispatcher->addSubscriber($subscriber);
- }
-
- /**
- * {@inheritdoc}
- */
- public function removeListener($eventName, $listener)
- {
- return $this->dispatcher->removeListener($eventName, $listener);
- }
-
- /**
- * {@inheritdoc}
- */
- public function removeSubscriber(EventSubscriberInterface $subscriber)
- {
- return $this->dispatcher->removeSubscriber($subscriber);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getListeners($eventName = null): array
- {
- return $this->dispatcher->getListeners($eventName);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getListenerPriority($eventName, $listener): ?int
- {
- return $this->dispatcher->getListenerPriority($eventName, $listener);
- }
-
- /**
- * {@inheritdoc}
- */
- public function hasListeners($eventName = null): bool
- {
- return $this->dispatcher->hasListeners($eventName);
- }
-
- /**
- * Proxies all method calls to the original event dispatcher.
- */
- public function __call($method, $arguments)
- {
- return $this->dispatcher->{$method}(...$arguments);
+ return $dispatcher;
}
}
diff --git a/vendor/symfony/event-dispatcher/LegacyEventProxy.php b/vendor/symfony/event-dispatcher/LegacyEventProxy.php
deleted file mode 100644
index 45ee251d6..000000000
--- a/vendor/symfony/event-dispatcher/LegacyEventProxy.php
+++ /dev/null
@@ -1,62 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\EventDispatcher;
-
-use Psr\EventDispatcher\StoppableEventInterface;
-use Symfony\Contracts\EventDispatcher\Event as ContractsEvent;
-
-/**
- * @internal to be removed in 5.0.
- */
-final class LegacyEventProxy extends Event
-{
- private $event;
-
- /**
- * @param object $event
- */
- public function __construct($event)
- {
- $this->event = $event;
- }
-
- /**
- * @return object $event
- */
- public function getEvent()
- {
- return $this->event;
- }
-
- public function isPropagationStopped(): bool
- {
- if (!$this->event instanceof ContractsEvent && !$this->event instanceof StoppableEventInterface) {
- return false;
- }
-
- return $this->event->isPropagationStopped();
- }
-
- public function stopPropagation()
- {
- if (!$this->event instanceof ContractsEvent) {
- return;
- }
-
- $this->event->stopPropagation();
- }
-
- public function __call($name, $args)
- {
- return $this->event->{$name}(...$args);
- }
-}
diff --git a/vendor/symfony/event-dispatcher/composer.json b/vendor/symfony/event-dispatcher/composer.json
index 55c2716a6..32b42e408 100644
--- a/vendor/symfony/event-dispatcher/composer.json
+++ b/vendor/symfony/event-dispatcher/composer.json
@@ -16,26 +16,27 @@
}
],
"require": {
- "php": ">=7.1.3",
- "symfony/event-dispatcher-contracts": "^1.1",
+ "php": ">=7.2.5",
+ "symfony/deprecation-contracts": "^2.1|^3",
+ "symfony/event-dispatcher-contracts": "^2|^3",
"symfony/polyfill-php80": "^1.16"
},
"require-dev": {
- "symfony/dependency-injection": "^3.4|^4.0|^5.0",
- "symfony/expression-language": "^3.4|^4.0|^5.0",
- "symfony/config": "^3.4|^4.0|^5.0",
- "symfony/error-handler": "~3.4|~4.4",
- "symfony/http-foundation": "^3.4|^4.0|^5.0",
- "symfony/service-contracts": "^1.1|^2",
- "symfony/stopwatch": "^3.4|^4.0|^5.0",
+ "symfony/dependency-injection": "^4.4|^5.0|^6.0",
+ "symfony/expression-language": "^4.4|^5.0|^6.0",
+ "symfony/config": "^4.4|^5.0|^6.0",
+ "symfony/error-handler": "^4.4|^5.0|^6.0",
+ "symfony/http-foundation": "^4.4|^5.0|^6.0",
+ "symfony/service-contracts": "^1.1|^2|^3",
+ "symfony/stopwatch": "^4.4|^5.0|^6.0",
"psr/log": "^1|^2|^3"
},
"conflict": {
- "symfony/dependency-injection": "<3.4"
+ "symfony/dependency-injection": "<4.4"
},
"provide": {
"psr/event-dispatcher-implementation": "1.0",
- "symfony/event-dispatcher-implementation": "1.1"
+ "symfony/event-dispatcher-implementation": "2.0"
},
"suggest": {
"symfony/dependency-injection": "",
diff --git a/vendor/symfony/polyfill-ctype/Ctype.php b/vendor/symfony/polyfill-ctype/Ctype.php
new file mode 100644
index 000000000..ba75a2c95
--- /dev/null
+++ b/vendor/symfony/polyfill-ctype/Ctype.php
@@ -0,0 +1,232 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Polyfill\Ctype;
+
+/**
+ * Ctype implementation through regex.
+ *
+ * @internal
+ *
+ * @author Gert de Pagter
+ */
+final class Ctype
+{
+ /**
+ * Returns TRUE if every character in text is either a letter or a digit, FALSE otherwise.
+ *
+ * @see https://php.net/ctype-alnum
+ *
+ * @param mixed $text
+ *
+ * @return bool
+ */
+ public static function ctype_alnum($text)
+ {
+ $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
+
+ return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z0-9]/', $text);
+ }
+
+ /**
+ * Returns TRUE if every character in text is a letter, FALSE otherwise.
+ *
+ * @see https://php.net/ctype-alpha
+ *
+ * @param mixed $text
+ *
+ * @return bool
+ */
+ public static function ctype_alpha($text)
+ {
+ $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
+
+ return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z]/', $text);
+ }
+
+ /**
+ * Returns TRUE if every character in text is a control character from the current locale, FALSE otherwise.
+ *
+ * @see https://php.net/ctype-cntrl
+ *
+ * @param mixed $text
+ *
+ * @return bool
+ */
+ public static function ctype_cntrl($text)
+ {
+ $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
+
+ return \is_string($text) && '' !== $text && !preg_match('/[^\x00-\x1f\x7f]/', $text);
+ }
+
+ /**
+ * Returns TRUE if every character in the string text is a decimal digit, FALSE otherwise.
+ *
+ * @see https://php.net/ctype-digit
+ *
+ * @param mixed $text
+ *
+ * @return bool
+ */
+ public static function ctype_digit($text)
+ {
+ $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
+
+ return \is_string($text) && '' !== $text && !preg_match('/[^0-9]/', $text);
+ }
+
+ /**
+ * Returns TRUE if every character in text is printable and actually creates visible output (no white space), FALSE otherwise.
+ *
+ * @see https://php.net/ctype-graph
+ *
+ * @param mixed $text
+ *
+ * @return bool
+ */
+ public static function ctype_graph($text)
+ {
+ $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
+
+ return \is_string($text) && '' !== $text && !preg_match('/[^!-~]/', $text);
+ }
+
+ /**
+ * Returns TRUE if every character in text is a lowercase letter.
+ *
+ * @see https://php.net/ctype-lower
+ *
+ * @param mixed $text
+ *
+ * @return bool
+ */
+ public static function ctype_lower($text)
+ {
+ $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
+
+ return \is_string($text) && '' !== $text && !preg_match('/[^a-z]/', $text);
+ }
+
+ /**
+ * Returns TRUE if every character in text will actually create output (including blanks). Returns FALSE if text contains control characters or characters that do not have any output or control function at all.
+ *
+ * @see https://php.net/ctype-print
+ *
+ * @param mixed $text
+ *
+ * @return bool
+ */
+ public static function ctype_print($text)
+ {
+ $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
+
+ return \is_string($text) && '' !== $text && !preg_match('/[^ -~]/', $text);
+ }
+
+ /**
+ * Returns TRUE if every character in text is printable, but neither letter, digit or blank, FALSE otherwise.
+ *
+ * @see https://php.net/ctype-punct
+ *
+ * @param mixed $text
+ *
+ * @return bool
+ */
+ public static function ctype_punct($text)
+ {
+ $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
+
+ return \is_string($text) && '' !== $text && !preg_match('/[^!-\/\:-@\[-`\{-~]/', $text);
+ }
+
+ /**
+ * Returns TRUE if every character in text creates some sort of white space, FALSE otherwise. Besides the blank character this also includes tab, vertical tab, line feed, carriage return and form feed characters.
+ *
+ * @see https://php.net/ctype-space
+ *
+ * @param mixed $text
+ *
+ * @return bool
+ */
+ public static function ctype_space($text)
+ {
+ $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
+
+ return \is_string($text) && '' !== $text && !preg_match('/[^\s]/', $text);
+ }
+
+ /**
+ * Returns TRUE if every character in text is an uppercase letter.
+ *
+ * @see https://php.net/ctype-upper
+ *
+ * @param mixed $text
+ *
+ * @return bool
+ */
+ public static function ctype_upper($text)
+ {
+ $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
+
+ return \is_string($text) && '' !== $text && !preg_match('/[^A-Z]/', $text);
+ }
+
+ /**
+ * Returns TRUE if every character in text is a hexadecimal 'digit', that is a decimal digit or a character from [A-Fa-f] , FALSE otherwise.
+ *
+ * @see https://php.net/ctype-xdigit
+ *
+ * @param mixed $text
+ *
+ * @return bool
+ */
+ public static function ctype_xdigit($text)
+ {
+ $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__);
+
+ return \is_string($text) && '' !== $text && !preg_match('/[^A-Fa-f0-9]/', $text);
+ }
+
+ /**
+ * Converts integers to their char versions according to normal ctype behaviour, if needed.
+ *
+ * If an integer between -128 and 255 inclusive is provided,
+ * it is interpreted as the ASCII value of a single character
+ * (negative values have 256 added in order to allow characters in the Extended ASCII range).
+ * Any other integer is interpreted as a string containing the decimal digits of the integer.
+ *
+ * @param mixed $int
+ * @param string $function
+ *
+ * @return mixed
+ */
+ private static function convert_int_to_char_for_ctype($int, $function)
+ {
+ if (!\is_int($int)) {
+ return $int;
+ }
+
+ if ($int < -128 || $int > 255) {
+ return (string) $int;
+ }
+
+ if (\PHP_VERSION_ID >= 80100) {
+ @trigger_error($function.'(): Argument of type int will be interpreted as string in the future', \E_USER_DEPRECATED);
+ }
+
+ if ($int < 0) {
+ $int += 256;
+ }
+
+ return \chr($int);
+ }
+}
diff --git a/vendor/symfony/polyfill-ctype/LICENSE b/vendor/symfony/polyfill-ctype/LICENSE
new file mode 100644
index 000000000..3f853aaf3
--- /dev/null
+++ b/vendor/symfony/polyfill-ctype/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2018-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/vendor/symfony/polyfill-ctype/README.md b/vendor/symfony/polyfill-ctype/README.md
new file mode 100644
index 000000000..b144d03c3
--- /dev/null
+++ b/vendor/symfony/polyfill-ctype/README.md
@@ -0,0 +1,12 @@
+Symfony Polyfill / Ctype
+========================
+
+This component provides `ctype_*` functions to users who run php versions without the ctype extension.
+
+More information can be found in the
+[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).
+
+License
+=======
+
+This library is released under the [MIT license](LICENSE).
diff --git a/vendor/symfony/polyfill-ctype/bootstrap.php b/vendor/symfony/polyfill-ctype/bootstrap.php
new file mode 100644
index 000000000..d54524b31
--- /dev/null
+++ b/vendor/symfony/polyfill-ctype/bootstrap.php
@@ -0,0 +1,50 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+use Symfony\Polyfill\Ctype as p;
+
+if (\PHP_VERSION_ID >= 80000) {
+ return require __DIR__.'/bootstrap80.php';
+}
+
+if (!function_exists('ctype_alnum')) {
+ function ctype_alnum($text) { return p\Ctype::ctype_alnum($text); }
+}
+if (!function_exists('ctype_alpha')) {
+ function ctype_alpha($text) { return p\Ctype::ctype_alpha($text); }
+}
+if (!function_exists('ctype_cntrl')) {
+ function ctype_cntrl($text) { return p\Ctype::ctype_cntrl($text); }
+}
+if (!function_exists('ctype_digit')) {
+ function ctype_digit($text) { return p\Ctype::ctype_digit($text); }
+}
+if (!function_exists('ctype_graph')) {
+ function ctype_graph($text) { return p\Ctype::ctype_graph($text); }
+}
+if (!function_exists('ctype_lower')) {
+ function ctype_lower($text) { return p\Ctype::ctype_lower($text); }
+}
+if (!function_exists('ctype_print')) {
+ function ctype_print($text) { return p\Ctype::ctype_print($text); }
+}
+if (!function_exists('ctype_punct')) {
+ function ctype_punct($text) { return p\Ctype::ctype_punct($text); }
+}
+if (!function_exists('ctype_space')) {
+ function ctype_space($text) { return p\Ctype::ctype_space($text); }
+}
+if (!function_exists('ctype_upper')) {
+ function ctype_upper($text) { return p\Ctype::ctype_upper($text); }
+}
+if (!function_exists('ctype_xdigit')) {
+ function ctype_xdigit($text) { return p\Ctype::ctype_xdigit($text); }
+}
diff --git a/vendor/symfony/polyfill-ctype/bootstrap80.php b/vendor/symfony/polyfill-ctype/bootstrap80.php
new file mode 100644
index 000000000..ab2f8611d
--- /dev/null
+++ b/vendor/symfony/polyfill-ctype/bootstrap80.php
@@ -0,0 +1,46 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+use Symfony\Polyfill\Ctype as p;
+
+if (!function_exists('ctype_alnum')) {
+ function ctype_alnum(mixed $text): bool { return p\Ctype::ctype_alnum($text); }
+}
+if (!function_exists('ctype_alpha')) {
+ function ctype_alpha(mixed $text): bool { return p\Ctype::ctype_alpha($text); }
+}
+if (!function_exists('ctype_cntrl')) {
+ function ctype_cntrl(mixed $text): bool { return p\Ctype::ctype_cntrl($text); }
+}
+if (!function_exists('ctype_digit')) {
+ function ctype_digit(mixed $text): bool { return p\Ctype::ctype_digit($text); }
+}
+if (!function_exists('ctype_graph')) {
+ function ctype_graph(mixed $text): bool { return p\Ctype::ctype_graph($text); }
+}
+if (!function_exists('ctype_lower')) {
+ function ctype_lower(mixed $text): bool { return p\Ctype::ctype_lower($text); }
+}
+if (!function_exists('ctype_print')) {
+ function ctype_print(mixed $text): bool { return p\Ctype::ctype_print($text); }
+}
+if (!function_exists('ctype_punct')) {
+ function ctype_punct(mixed $text): bool { return p\Ctype::ctype_punct($text); }
+}
+if (!function_exists('ctype_space')) {
+ function ctype_space(mixed $text): bool { return p\Ctype::ctype_space($text); }
+}
+if (!function_exists('ctype_upper')) {
+ function ctype_upper(mixed $text): bool { return p\Ctype::ctype_upper($text); }
+}
+if (!function_exists('ctype_xdigit')) {
+ function ctype_xdigit(mixed $text): bool { return p\Ctype::ctype_xdigit($text); }
+}
diff --git a/vendor/symfony/polyfill-ctype/composer.json b/vendor/symfony/polyfill-ctype/composer.json
new file mode 100644
index 000000000..1b3efff57
--- /dev/null
+++ b/vendor/symfony/polyfill-ctype/composer.json
@@ -0,0 +1,41 @@
+{
+ "name": "symfony/polyfill-ctype",
+ "type": "library",
+ "description": "Symfony polyfill for ctype functions",
+ "keywords": ["polyfill", "compatibility", "portable", "ctype"],
+ "homepage": "https://symfony.com",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Gert de Pagter",
+ "email": "BackEndTea@gmail.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=7.1"
+ },
+ "provide": {
+ "ext-ctype": "*"
+ },
+ "autoload": {
+ "psr-4": { "Symfony\\Polyfill\\Ctype\\": "" },
+ "files": [ "bootstrap.php" ]
+ },
+ "suggest": {
+ "ext-ctype": "For best performance"
+ },
+ "minimum-stability": "dev",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.27-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ }
+}
diff --git a/vendor/symfony/polyfill-intl-grapheme/Grapheme.php b/vendor/symfony/polyfill-intl-grapheme/Grapheme.php
new file mode 100644
index 000000000..5373f1685
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-grapheme/Grapheme.php
@@ -0,0 +1,247 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Polyfill\Intl\Grapheme;
+
+\define('SYMFONY_GRAPHEME_CLUSTER_RX', ((float) \PCRE_VERSION < 10 ? (float) \PCRE_VERSION >= 8.32 : (float) \PCRE_VERSION >= 10.39) ? '\X' : Grapheme::GRAPHEME_CLUSTER_RX);
+
+/**
+ * Partial intl implementation in pure PHP.
+ *
+ * Implemented:
+ * - grapheme_extract - Extract a sequence of grapheme clusters from a text buffer, which must be encoded in UTF-8
+ * - grapheme_stripos - Find position (in grapheme units) of first occurrence of a case-insensitive string
+ * - grapheme_stristr - Returns part of haystack string from the first occurrence of case-insensitive needle to the end of haystack
+ * - grapheme_strlen - Get string length in grapheme units
+ * - grapheme_strpos - Find position (in grapheme units) of first occurrence of a string
+ * - grapheme_strripos - Find position (in grapheme units) of last occurrence of a case-insensitive string
+ * - grapheme_strrpos - Find position (in grapheme units) of last occurrence of a string
+ * - grapheme_strstr - Returns part of haystack string from the first occurrence of needle to the end of haystack
+ * - grapheme_substr - Return part of a string
+ *
+ * @author Nicolas Grekas
+ *
+ * @internal
+ */
+final class Grapheme
+{
+ // (CRLF|([ZWNJ-ZWJ]|T+|L*(LV?V+|LV|LVT)T*|L+|[^Control])[Extend]*|[Control])
+ // This regular expression is a work around for http://bugs.exim.org/1279
+ public const GRAPHEME_CLUSTER_RX = '(?:\r\n|(?:[ -~\x{200C}\x{200D}]|[ᆨ-ᇹ]+|[ᄀ-ᅟ]*(?:[가개갸걔거게겨계고과괘괴교구궈궤귀규그긔기까깨꺄꺠꺼께껴꼐꼬꽈꽤꾀꾜꾸꿔꿰뀌뀨끄끠끼나내냐냬너네녀녜노놔놰뇌뇨누눠눼뉘뉴느늬니다대댜댸더데뎌뎨도돠돼되됴두둬뒈뒤듀드듸디따때땨떄떠떼뗘뗴또똬뙈뙤뚀뚜뚸뛔뛰뜌뜨띄띠라래랴럐러레려례로롸뢔뢰료루뤄뤠뤼류르릐리마매먀먜머메며몌모뫄뫠뫼묘무뭐뭬뮈뮤므믜미바배뱌뱨버베벼볘보봐봬뵈뵤부붜붸뷔뷰브븨비빠빼뺘뺴뻐뻬뼈뼤뽀뽜뽸뾔뾰뿌뿨쀄쀠쀼쁘쁴삐사새샤섀서세셔셰소솨쇄쇠쇼수숴쉐쉬슈스싀시싸쌔쌰썌써쎄쎠쎼쏘쏴쐐쐬쑈쑤쒀쒜쒸쓔쓰씌씨아애야얘어에여예오와왜외요우워웨위유으의이자재쟈쟤저제져졔조좌좨죄죠주줘줴쥐쥬즈즤지짜째쨔쨰쩌쩨쪄쪠쪼쫘쫴쬐쬬쭈쭤쮀쮜쮸쯔쯰찌차채챠챼처체쳐쳬초촤쵀최쵸추춰췌취츄츠츼치카캐캬컈커케켜켸코콰쾌쾨쿄쿠쿼퀘퀴큐크킈키타태탸턔터테텨톄토톼퇘퇴툐투퉈퉤튀튜트틔티파패퍄퍠퍼페펴폐포퐈퐤푀표푸풔풰퓌퓨프픠피하해햐햬허헤혀혜호화홰회효후훠훼휘휴흐희히]?[ᅠ-ᆢ]+|[가-힣])[ᆨ-ᇹ]*|[ᄀ-ᅟ]+|[^\p{Cc}\p{Cf}\p{Zl}\p{Zp}])[\p{Mn}\p{Me}\x{09BE}\x{09D7}\x{0B3E}\x{0B57}\x{0BBE}\x{0BD7}\x{0CC2}\x{0CD5}\x{0CD6}\x{0D3E}\x{0D57}\x{0DCF}\x{0DDF}\x{200C}\x{200D}\x{1D165}\x{1D16E}-\x{1D172}]*|[\p{Cc}\p{Cf}\p{Zl}\p{Zp}])';
+
+ private const CASE_FOLD = [
+ ['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"],
+ ['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'],
+ ];
+
+ public static function grapheme_extract($s, $size, $type = \GRAPHEME_EXTR_COUNT, $start = 0, &$next = 0)
+ {
+ if (0 > $start) {
+ $start = \strlen($s) + $start;
+ }
+
+ if (!\is_scalar($s)) {
+ $hasError = false;
+ set_error_handler(function () use (&$hasError) { $hasError = true; });
+ $next = substr($s, $start);
+ restore_error_handler();
+ if ($hasError) {
+ substr($s, $start);
+ $s = '';
+ } else {
+ $s = $next;
+ }
+ } else {
+ $s = substr($s, $start);
+ }
+ $size = (int) $size;
+ $type = (int) $type;
+ $start = (int) $start;
+
+ if (\GRAPHEME_EXTR_COUNT !== $type && \GRAPHEME_EXTR_MAXBYTES !== $type && \GRAPHEME_EXTR_MAXCHARS !== $type) {
+ if (80000 > \PHP_VERSION_ID) {
+ return false;
+ }
+
+ throw new \ValueError('grapheme_extract(): Argument #3 ($type) must be one of GRAPHEME_EXTR_COUNT, GRAPHEME_EXTR_MAXBYTES, or GRAPHEME_EXTR_MAXCHARS');
+ }
+
+ if (!isset($s[0]) || 0 > $size || 0 > $start) {
+ return false;
+ }
+ if (0 === $size) {
+ return '';
+ }
+
+ $next = $start;
+
+ $s = preg_split('/('.SYMFONY_GRAPHEME_CLUSTER_RX.')/u', "\r\n".$s, $size + 1, \PREG_SPLIT_NO_EMPTY | \PREG_SPLIT_DELIM_CAPTURE);
+
+ if (!isset($s[1])) {
+ return false;
+ }
+
+ $i = 1;
+ $ret = '';
+
+ do {
+ if (\GRAPHEME_EXTR_COUNT === $type) {
+ --$size;
+ } elseif (\GRAPHEME_EXTR_MAXBYTES === $type) {
+ $size -= \strlen($s[$i]);
+ } else {
+ $size -= iconv_strlen($s[$i], 'UTF-8//IGNORE');
+ }
+
+ if ($size >= 0) {
+ $ret .= $s[$i];
+ }
+ } while (isset($s[++$i]) && $size > 0);
+
+ $next += \strlen($ret);
+
+ return $ret;
+ }
+
+ public static function grapheme_strlen($s)
+ {
+ preg_replace('/'.SYMFONY_GRAPHEME_CLUSTER_RX.'/u', '', $s, -1, $len);
+
+ return 0 === $len && '' !== $s ? null : $len;
+ }
+
+ public static function grapheme_substr($s, $start, $len = null)
+ {
+ if (null === $len) {
+ $len = 2147483647;
+ }
+
+ preg_match_all('/'.SYMFONY_GRAPHEME_CLUSTER_RX.'/u', $s, $s);
+
+ $slen = \count($s[0]);
+ $start = (int) $start;
+
+ if (0 > $start) {
+ $start += $slen;
+ }
+ if (0 > $start) {
+ if (\PHP_VERSION_ID < 80000) {
+ return false;
+ }
+
+ $start = 0;
+ }
+ if ($start >= $slen) {
+ return \PHP_VERSION_ID >= 80000 ? '' : false;
+ }
+
+ $rem = $slen - $start;
+
+ if (0 > $len) {
+ $len += $rem;
+ }
+ if (0 === $len) {
+ return '';
+ }
+ if (0 > $len) {
+ return \PHP_VERSION_ID >= 80000 ? '' : false;
+ }
+ if ($len > $rem) {
+ $len = $rem;
+ }
+
+ return implode('', \array_slice($s[0], $start, $len));
+ }
+
+ public static function grapheme_strpos($s, $needle, $offset = 0)
+ {
+ return self::grapheme_position($s, $needle, $offset, 0);
+ }
+
+ public static function grapheme_stripos($s, $needle, $offset = 0)
+ {
+ return self::grapheme_position($s, $needle, $offset, 1);
+ }
+
+ public static function grapheme_strrpos($s, $needle, $offset = 0)
+ {
+ return self::grapheme_position($s, $needle, $offset, 2);
+ }
+
+ public static function grapheme_strripos($s, $needle, $offset = 0)
+ {
+ return self::grapheme_position($s, $needle, $offset, 3);
+ }
+
+ public static function grapheme_stristr($s, $needle, $beforeNeedle = false)
+ {
+ return mb_stristr($s, $needle, $beforeNeedle, 'UTF-8');
+ }
+
+ public static function grapheme_strstr($s, $needle, $beforeNeedle = false)
+ {
+ return mb_strstr($s, $needle, $beforeNeedle, 'UTF-8');
+ }
+
+ private static function grapheme_position($s, $needle, $offset, $mode)
+ {
+ $needle = (string) $needle;
+ if (80000 > \PHP_VERSION_ID && !preg_match('/./us', $needle)) {
+ return false;
+ }
+ $s = (string) $s;
+ if (!preg_match('/./us', $s)) {
+ return false;
+ }
+ if ($offset > 0) {
+ $s = self::grapheme_substr($s, $offset);
+ } elseif ($offset < 0) {
+ if (2 > $mode) {
+ $offset += self::grapheme_strlen($s);
+ $s = self::grapheme_substr($s, $offset);
+ if (0 > $offset) {
+ $offset = 0;
+ }
+ } elseif (0 > $offset += self::grapheme_strlen($needle)) {
+ $s = self::grapheme_substr($s, 0, $offset);
+ $offset = 0;
+ } else {
+ $offset = 0;
+ }
+ }
+
+ // As UTF-8 is self-synchronizing, and we have ensured the strings are valid UTF-8,
+ // we can use normal binary string functions here. For case-insensitive searches,
+ // case fold the strings first.
+ $caseInsensitive = $mode & 1;
+ $reverse = $mode & 2;
+ if ($caseInsensitive) {
+ // Use the same case folding mode as mbstring does for mb_stripos().
+ // Stick to SIMPLE case folding to avoid changing the length of the string, which
+ // might result in offsets being shifted.
+ $mode = \defined('MB_CASE_FOLD_SIMPLE') ? \MB_CASE_FOLD_SIMPLE : \MB_CASE_LOWER;
+ $s = mb_convert_case($s, $mode, 'UTF-8');
+ $needle = mb_convert_case($needle, $mode, 'UTF-8');
+
+ if (!\defined('MB_CASE_FOLD_SIMPLE')) {
+ $s = str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $s);
+ $needle = str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $needle);
+ }
+ }
+ if ($reverse) {
+ $needlePos = strrpos($s, $needle);
+ } else {
+ $needlePos = strpos($s, $needle);
+ }
+
+ return false !== $needlePos ? self::grapheme_strlen(substr($s, 0, $needlePos)) + $offset : false;
+ }
+}
diff --git a/vendor/symfony/polyfill-intl-grapheme/LICENSE b/vendor/symfony/polyfill-intl-grapheme/LICENSE
new file mode 100644
index 000000000..4cd8bdd30
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-grapheme/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2015-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/vendor/symfony/polyfill-intl-grapheme/README.md b/vendor/symfony/polyfill-intl-grapheme/README.md
new file mode 100644
index 000000000..f55d92c5c
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-grapheme/README.md
@@ -0,0 +1,31 @@
+Symfony Polyfill / Intl: Grapheme
+=================================
+
+This component provides a partial, native PHP implementation of the
+[Grapheme functions](https://php.net/intl.grapheme) from the
+[Intl](https://php.net/intl) extension.
+
+- [`grapheme_extract`](https://php.net/grapheme_extract): Extract a sequence of grapheme
+ clusters from a text buffer, which must be encoded in UTF-8
+- [`grapheme_stripos`](https://php.net/grapheme_stripos): Find position (in grapheme units)
+ of first occurrence of a case-insensitive string
+- [`grapheme_stristr`](https://php.net/grapheme_stristr): Returns part of haystack string
+ from the first occurrence of case-insensitive needle to the end of haystack
+- [`grapheme_strlen`](https://php.net/grapheme_strlen): Get string length in grapheme units
+- [`grapheme_strpos`](https://php.net/grapheme_strpos): Find position (in grapheme units)
+ of first occurrence of a string
+- [`grapheme_strripos`](https://php.net/grapheme_strripos): Find position (in grapheme units)
+ of last occurrence of a case-insensitive string
+- [`grapheme_strrpos`](https://php.net/grapheme_strrpos): Find position (in grapheme units)
+ of last occurrence of a string
+- [`grapheme_strstr`](https://php.net/grapheme_strstr): Returns part of haystack string from
+ the first occurrence of needle to the end of haystack
+- [`grapheme_substr`](https://php.net/grapheme_substr): Return part of a string
+
+More information can be found in the
+[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).
+
+License
+=======
+
+This library is released under the [MIT license](LICENSE).
diff --git a/vendor/symfony/polyfill-intl-grapheme/bootstrap.php b/vendor/symfony/polyfill-intl-grapheme/bootstrap.php
new file mode 100644
index 000000000..a9ea03c7e
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-grapheme/bootstrap.php
@@ -0,0 +1,58 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+use Symfony\Polyfill\Intl\Grapheme as p;
+
+if (extension_loaded('intl')) {
+ return;
+}
+
+if (\PHP_VERSION_ID >= 80000) {
+ return require __DIR__.'/bootstrap80.php';
+}
+
+if (!defined('GRAPHEME_EXTR_COUNT')) {
+ define('GRAPHEME_EXTR_COUNT', 0);
+}
+if (!defined('GRAPHEME_EXTR_MAXBYTES')) {
+ define('GRAPHEME_EXTR_MAXBYTES', 1);
+}
+if (!defined('GRAPHEME_EXTR_MAXCHARS')) {
+ define('GRAPHEME_EXTR_MAXCHARS', 2);
+}
+
+if (!function_exists('grapheme_extract')) {
+ function grapheme_extract($haystack, $size, $type = 0, $start = 0, &$next = 0) { return p\Grapheme::grapheme_extract($haystack, $size, $type, $start, $next); }
+}
+if (!function_exists('grapheme_stripos')) {
+ function grapheme_stripos($haystack, $needle, $offset = 0) { return p\Grapheme::grapheme_stripos($haystack, $needle, $offset); }
+}
+if (!function_exists('grapheme_stristr')) {
+ function grapheme_stristr($haystack, $needle, $beforeNeedle = false) { return p\Grapheme::grapheme_stristr($haystack, $needle, $beforeNeedle); }
+}
+if (!function_exists('grapheme_strlen')) {
+ function grapheme_strlen($input) { return p\Grapheme::grapheme_strlen($input); }
+}
+if (!function_exists('grapheme_strpos')) {
+ function grapheme_strpos($haystack, $needle, $offset = 0) { return p\Grapheme::grapheme_strpos($haystack, $needle, $offset); }
+}
+if (!function_exists('grapheme_strripos')) {
+ function grapheme_strripos($haystack, $needle, $offset = 0) { return p\Grapheme::grapheme_strripos($haystack, $needle, $offset); }
+}
+if (!function_exists('grapheme_strrpos')) {
+ function grapheme_strrpos($haystack, $needle, $offset = 0) { return p\Grapheme::grapheme_strrpos($haystack, $needle, $offset); }
+}
+if (!function_exists('grapheme_strstr')) {
+ function grapheme_strstr($haystack, $needle, $beforeNeedle = false) { return p\Grapheme::grapheme_strstr($haystack, $needle, $beforeNeedle); }
+}
+if (!function_exists('grapheme_substr')) {
+ function grapheme_substr($string, $offset, $length = null) { return p\Grapheme::grapheme_substr($string, $offset, $length); }
+}
diff --git a/vendor/symfony/polyfill-intl-grapheme/bootstrap80.php b/vendor/symfony/polyfill-intl-grapheme/bootstrap80.php
new file mode 100644
index 000000000..b8c078677
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-grapheme/bootstrap80.php
@@ -0,0 +1,50 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+use Symfony\Polyfill\Intl\Grapheme as p;
+
+if (!defined('GRAPHEME_EXTR_COUNT')) {
+ define('GRAPHEME_EXTR_COUNT', 0);
+}
+if (!defined('GRAPHEME_EXTR_MAXBYTES')) {
+ define('GRAPHEME_EXTR_MAXBYTES', 1);
+}
+if (!defined('GRAPHEME_EXTR_MAXCHARS')) {
+ define('GRAPHEME_EXTR_MAXCHARS', 2);
+}
+
+if (!function_exists('grapheme_extract')) {
+ function grapheme_extract(?string $haystack, ?int $size, ?int $type = GRAPHEME_EXTR_COUNT, ?int $offset = 0, &$next = null): string|false { return p\Grapheme::grapheme_extract((string) $haystack, (int) $size, (int) $type, (int) $offset, $next); }
+}
+if (!function_exists('grapheme_stripos')) {
+ function grapheme_stripos(?string $haystack, ?string $needle, ?int $offset = 0): int|false { return p\Grapheme::grapheme_stripos((string) $haystack, (string) $needle, (int) $offset); }
+}
+if (!function_exists('grapheme_stristr')) {
+ function grapheme_stristr(?string $haystack, ?string $needle, ?bool $beforeNeedle = false): string|false { return p\Grapheme::grapheme_stristr((string) $haystack, (string) $needle, (bool) $beforeNeedle); }
+}
+if (!function_exists('grapheme_strlen')) {
+ function grapheme_strlen(?string $string): int|false|null { return p\Grapheme::grapheme_strlen((string) $string); }
+}
+if (!function_exists('grapheme_strpos')) {
+ function grapheme_strpos(?string $haystack, ?string $needle, ?int $offset = 0): int|false { return p\Grapheme::grapheme_strpos((string) $haystack, (string) $needle, (int) $offset); }
+}
+if (!function_exists('grapheme_strripos')) {
+ function grapheme_strripos(?string $haystack, ?string $needle, ?int $offset = 0): int|false { return p\Grapheme::grapheme_strripos((string) $haystack, (string) $needle, (int) $offset); }
+}
+if (!function_exists('grapheme_strrpos')) {
+ function grapheme_strrpos(?string $haystack, ?string $needle, ?int $offset = 0): int|false { return p\Grapheme::grapheme_strrpos((string) $haystack, (string) $needle, (int) $offset); }
+}
+if (!function_exists('grapheme_strstr')) {
+ function grapheme_strstr(?string $haystack, ?string $needle, ?bool $beforeNeedle = false): string|false { return p\Grapheme::grapheme_strstr((string) $haystack, (string) $needle, (bool) $beforeNeedle); }
+}
+if (!function_exists('grapheme_substr')) {
+ function grapheme_substr(?string $string, ?int $offset, ?int $length = null): string|false { return p\Grapheme::grapheme_substr((string) $string, (int) $offset, $length); }
+}
diff --git a/vendor/symfony/polyfill-intl-grapheme/composer.json b/vendor/symfony/polyfill-intl-grapheme/composer.json
new file mode 100644
index 000000000..fde5537fc
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-grapheme/composer.json
@@ -0,0 +1,38 @@
+{
+ "name": "symfony/polyfill-intl-grapheme",
+ "type": "library",
+ "description": "Symfony polyfill for intl's grapheme_* functions",
+ "keywords": ["polyfill", "shim", "compatibility", "portable", "intl", "grapheme"],
+ "homepage": "https://symfony.com",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=7.1"
+ },
+ "autoload": {
+ "psr-4": { "Symfony\\Polyfill\\Intl\\Grapheme\\": "" },
+ "files": [ "bootstrap.php" ]
+ },
+ "suggest": {
+ "ext-intl": "For best performance"
+ },
+ "minimum-stability": "dev",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.27-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ }
+}
diff --git a/vendor/symfony/polyfill-intl-normalizer/LICENSE b/vendor/symfony/polyfill-intl-normalizer/LICENSE
new file mode 100644
index 000000000..4cd8bdd30
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-normalizer/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2015-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/vendor/symfony/polyfill-intl-normalizer/Normalizer.php b/vendor/symfony/polyfill-intl-normalizer/Normalizer.php
new file mode 100644
index 000000000..81704ab37
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-normalizer/Normalizer.php
@@ -0,0 +1,310 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Polyfill\Intl\Normalizer;
+
+/**
+ * Normalizer is a PHP fallback implementation of the Normalizer class provided by the intl extension.
+ *
+ * It has been validated with Unicode 6.3 Normalization Conformance Test.
+ * See http://www.unicode.org/reports/tr15/ for detailed info about Unicode normalizations.
+ *
+ * @author Nicolas Grekas
+ *
+ * @internal
+ */
+class Normalizer
+{
+ public const FORM_D = \Normalizer::FORM_D;
+ public const FORM_KD = \Normalizer::FORM_KD;
+ public const FORM_C = \Normalizer::FORM_C;
+ public const FORM_KC = \Normalizer::FORM_KC;
+ public const NFD = \Normalizer::NFD;
+ public const NFKD = \Normalizer::NFKD;
+ public const NFC = \Normalizer::NFC;
+ public const NFKC = \Normalizer::NFKC;
+
+ private static $C;
+ private static $D;
+ private static $KD;
+ private static $cC;
+ private static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4];
+ private static $ASCII = "\x20\x65\x69\x61\x73\x6E\x74\x72\x6F\x6C\x75\x64\x5D\x5B\x63\x6D\x70\x27\x0A\x67\x7C\x68\x76\x2E\x66\x62\x2C\x3A\x3D\x2D\x71\x31\x30\x43\x32\x2A\x79\x78\x29\x28\x4C\x39\x41\x53\x2F\x50\x22\x45\x6A\x4D\x49\x6B\x33\x3E\x35\x54\x3C\x44\x34\x7D\x42\x7B\x38\x46\x77\x52\x36\x37\x55\x47\x4E\x3B\x4A\x7A\x56\x23\x48\x4F\x57\x5F\x26\x21\x4B\x3F\x58\x51\x25\x59\x5C\x09\x5A\x2B\x7E\x5E\x24\x40\x60\x7F\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F";
+
+ public static function isNormalized(string $s, int $form = self::FORM_C)
+ {
+ if (!\in_array($form, [self::NFD, self::NFKD, self::NFC, self::NFKC])) {
+ return false;
+ }
+ if (!isset($s[strspn($s, self::$ASCII)])) {
+ return true;
+ }
+ if (self::NFC == $form && preg_match('//u', $s) && !preg_match('/[^\x00-\x{2FF}]/u', $s)) {
+ return true;
+ }
+
+ return self::normalize($s, $form) === $s;
+ }
+
+ public static function normalize(string $s, int $form = self::FORM_C)
+ {
+ if (!preg_match('//u', $s)) {
+ return false;
+ }
+
+ switch ($form) {
+ case self::NFC: $C = true; $K = false; break;
+ case self::NFD: $C = false; $K = false; break;
+ case self::NFKC: $C = true; $K = true; break;
+ case self::NFKD: $C = false; $K = true; break;
+ default:
+ if (\defined('Normalizer::NONE') && \Normalizer::NONE == $form) {
+ return $s;
+ }
+
+ if (80000 > \PHP_VERSION_ID) {
+ return false;
+ }
+
+ throw new \ValueError('normalizer_normalize(): Argument #2 ($form) must be a a valid normalization form');
+ }
+
+ if ('' === $s) {
+ return '';
+ }
+
+ if ($K && null === self::$KD) {
+ self::$KD = self::getData('compatibilityDecomposition');
+ }
+
+ if (null === self::$D) {
+ self::$D = self::getData('canonicalDecomposition');
+ self::$cC = self::getData('combiningClass');
+ }
+
+ if (null !== $mbEncoding = (2 /* MB_OVERLOAD_STRING */ & (int) \ini_get('mbstring.func_overload')) ? mb_internal_encoding() : null) {
+ mb_internal_encoding('8bit');
+ }
+
+ $r = self::decompose($s, $K);
+
+ if ($C) {
+ if (null === self::$C) {
+ self::$C = self::getData('canonicalComposition');
+ }
+
+ $r = self::recompose($r);
+ }
+ if (null !== $mbEncoding) {
+ mb_internal_encoding($mbEncoding);
+ }
+
+ return $r;
+ }
+
+ private static function recompose($s)
+ {
+ $ASCII = self::$ASCII;
+ $compMap = self::$C;
+ $combClass = self::$cC;
+ $ulenMask = self::$ulenMask;
+
+ $result = $tail = '';
+
+ $i = $s[0] < "\x80" ? 1 : $ulenMask[$s[0] & "\xF0"];
+ $len = \strlen($s);
+
+ $lastUchr = substr($s, 0, $i);
+ $lastUcls = isset($combClass[$lastUchr]) ? 256 : 0;
+
+ while ($i < $len) {
+ if ($s[$i] < "\x80") {
+ // ASCII chars
+
+ if ($tail) {
+ $lastUchr .= $tail;
+ $tail = '';
+ }
+
+ if ($j = strspn($s, $ASCII, $i + 1)) {
+ $lastUchr .= substr($s, $i, $j);
+ $i += $j;
+ }
+
+ $result .= $lastUchr;
+ $lastUchr = $s[$i];
+ $lastUcls = 0;
+ ++$i;
+ continue;
+ }
+
+ $ulen = $ulenMask[$s[$i] & "\xF0"];
+ $uchr = substr($s, $i, $ulen);
+
+ if ($lastUchr < "\xE1\x84\x80" || "\xE1\x84\x92" < $lastUchr
+ || $uchr < "\xE1\x85\xA1" || "\xE1\x85\xB5" < $uchr
+ || $lastUcls) {
+ // Table lookup and combining chars composition
+
+ $ucls = $combClass[$uchr] ?? 0;
+
+ if (isset($compMap[$lastUchr.$uchr]) && (!$lastUcls || $lastUcls < $ucls)) {
+ $lastUchr = $compMap[$lastUchr.$uchr];
+ } elseif ($lastUcls = $ucls) {
+ $tail .= $uchr;
+ } else {
+ if ($tail) {
+ $lastUchr .= $tail;
+ $tail = '';
+ }
+
+ $result .= $lastUchr;
+ $lastUchr = $uchr;
+ }
+ } else {
+ // Hangul chars
+
+ $L = \ord($lastUchr[2]) - 0x80;
+ $V = \ord($uchr[2]) - 0xA1;
+ $T = 0;
+
+ $uchr = substr($s, $i + $ulen, 3);
+
+ if ("\xE1\x86\xA7" <= $uchr && $uchr <= "\xE1\x87\x82") {
+ $T = \ord($uchr[2]) - 0xA7;
+ 0 > $T && $T += 0x40;
+ $ulen += 3;
+ }
+
+ $L = 0xAC00 + ($L * 21 + $V) * 28 + $T;
+ $lastUchr = \chr(0xE0 | $L >> 12).\chr(0x80 | $L >> 6 & 0x3F).\chr(0x80 | $L & 0x3F);
+ }
+
+ $i += $ulen;
+ }
+
+ return $result.$lastUchr.$tail;
+ }
+
+ private static function decompose($s, $c)
+ {
+ $result = '';
+
+ $ASCII = self::$ASCII;
+ $decompMap = self::$D;
+ $combClass = self::$cC;
+ $ulenMask = self::$ulenMask;
+ if ($c) {
+ $compatMap = self::$KD;
+ }
+
+ $c = [];
+ $i = 0;
+ $len = \strlen($s);
+
+ while ($i < $len) {
+ if ($s[$i] < "\x80") {
+ // ASCII chars
+
+ if ($c) {
+ ksort($c);
+ $result .= implode('', $c);
+ $c = [];
+ }
+
+ $j = 1 + strspn($s, $ASCII, $i + 1);
+ $result .= substr($s, $i, $j);
+ $i += $j;
+ continue;
+ }
+
+ $ulen = $ulenMask[$s[$i] & "\xF0"];
+ $uchr = substr($s, $i, $ulen);
+ $i += $ulen;
+
+ if ($uchr < "\xEA\xB0\x80" || "\xED\x9E\xA3" < $uchr) {
+ // Table lookup
+
+ if ($uchr !== $j = $compatMap[$uchr] ?? ($decompMap[$uchr] ?? $uchr)) {
+ $uchr = $j;
+
+ $j = \strlen($uchr);
+ $ulen = $uchr[0] < "\x80" ? 1 : $ulenMask[$uchr[0] & "\xF0"];
+
+ if ($ulen != $j) {
+ // Put trailing chars in $s
+
+ $j -= $ulen;
+ $i -= $j;
+
+ if (0 > $i) {
+ $s = str_repeat(' ', -$i).$s;
+ $len -= $i;
+ $i = 0;
+ }
+
+ while ($j--) {
+ $s[$i + $j] = $uchr[$ulen + $j];
+ }
+
+ $uchr = substr($uchr, 0, $ulen);
+ }
+ }
+ if (isset($combClass[$uchr])) {
+ // Combining chars, for sorting
+
+ if (!isset($c[$combClass[$uchr]])) {
+ $c[$combClass[$uchr]] = '';
+ }
+ $c[$combClass[$uchr]] .= $uchr;
+ continue;
+ }
+ } else {
+ // Hangul chars
+
+ $uchr = unpack('C*', $uchr);
+ $j = (($uchr[1] - 224) << 12) + (($uchr[2] - 128) << 6) + $uchr[3] - 0xAC80;
+
+ $uchr = "\xE1\x84".\chr(0x80 + (int) ($j / 588))
+ ."\xE1\x85".\chr(0xA1 + (int) (($j % 588) / 28));
+
+ if ($j %= 28) {
+ $uchr .= $j < 25
+ ? ("\xE1\x86".\chr(0xA7 + $j))
+ : ("\xE1\x87".\chr(0x67 + $j));
+ }
+ }
+ if ($c) {
+ ksort($c);
+ $result .= implode('', $c);
+ $c = [];
+ }
+
+ $result .= $uchr;
+ }
+
+ if ($c) {
+ ksort($c);
+ $result .= implode('', $c);
+ }
+
+ return $result;
+ }
+
+ private static function getData($file)
+ {
+ if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) {
+ return require $file;
+ }
+
+ return false;
+ }
+}
diff --git a/vendor/symfony/polyfill-intl-normalizer/README.md b/vendor/symfony/polyfill-intl-normalizer/README.md
new file mode 100644
index 000000000..b9b762e85
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-normalizer/README.md
@@ -0,0 +1,14 @@
+Symfony Polyfill / Intl: Normalizer
+===================================
+
+This component provides a fallback implementation for the
+[`Normalizer`](https://php.net/Normalizer) class provided
+by the [Intl](https://php.net/intl) extension.
+
+More information can be found in the
+[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).
+
+License
+=======
+
+This library is released under the [MIT license](LICENSE).
diff --git a/vendor/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php b/vendor/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php
new file mode 100644
index 000000000..0fdfc890a
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php
@@ -0,0 +1,17 @@
+ 'À',
+ 'Á' => 'Á',
+ 'Â' => 'Â',
+ 'Ã' => 'Ã',
+ 'Ä' => 'Ä',
+ 'Å' => 'Å',
+ 'Ç' => 'Ç',
+ 'È' => 'È',
+ 'É' => 'É',
+ 'Ê' => 'Ê',
+ 'Ë' => 'Ë',
+ 'Ì' => 'Ì',
+ 'Í' => 'Í',
+ 'Î' => 'Î',
+ 'Ï' => 'Ï',
+ 'Ñ' => 'Ñ',
+ 'Ò' => 'Ò',
+ 'Ó' => 'Ó',
+ 'Ô' => 'Ô',
+ 'Õ' => 'Õ',
+ 'Ö' => 'Ö',
+ 'Ù' => 'Ù',
+ 'Ú' => 'Ú',
+ 'Û' => 'Û',
+ 'Ü' => 'Ü',
+ 'Ý' => 'Ý',
+ 'à' => 'à',
+ 'á' => 'á',
+ 'â' => 'â',
+ 'ã' => 'ã',
+ 'ä' => 'ä',
+ 'å' => 'å',
+ 'ç' => 'ç',
+ 'è' => 'è',
+ 'é' => 'é',
+ 'ê' => 'ê',
+ 'ë' => 'ë',
+ 'ì' => 'ì',
+ 'í' => 'í',
+ 'î' => 'î',
+ 'ï' => 'ï',
+ 'ñ' => 'ñ',
+ 'ò' => 'ò',
+ 'ó' => 'ó',
+ 'ô' => 'ô',
+ 'õ' => 'õ',
+ 'ö' => 'ö',
+ 'ù' => 'ù',
+ 'ú' => 'ú',
+ 'û' => 'û',
+ 'ü' => 'ü',
+ 'ý' => 'ý',
+ 'ÿ' => 'ÿ',
+ 'Ā' => 'Ā',
+ 'ā' => 'ā',
+ 'Ă' => 'Ă',
+ 'ă' => 'ă',
+ 'Ą' => 'Ą',
+ 'ą' => 'ą',
+ 'Ć' => 'Ć',
+ 'ć' => 'ć',
+ 'Ĉ' => 'Ĉ',
+ 'ĉ' => 'ĉ',
+ 'Ċ' => 'Ċ',
+ 'ċ' => 'ċ',
+ 'Č' => 'Č',
+ 'č' => 'č',
+ 'Ď' => 'Ď',
+ 'ď' => 'ď',
+ 'Ē' => 'Ē',
+ 'ē' => 'ē',
+ 'Ĕ' => 'Ĕ',
+ 'ĕ' => 'ĕ',
+ 'Ė' => 'Ė',
+ 'ė' => 'ė',
+ 'Ę' => 'Ę',
+ 'ę' => 'ę',
+ 'Ě' => 'Ě',
+ 'ě' => 'ě',
+ 'Ĝ' => 'Ĝ',
+ 'ĝ' => 'ĝ',
+ 'Ğ' => 'Ğ',
+ 'ğ' => 'ğ',
+ 'Ġ' => 'Ġ',
+ 'ġ' => 'ġ',
+ 'Ģ' => 'Ģ',
+ 'ģ' => 'ģ',
+ 'Ĥ' => 'Ĥ',
+ 'ĥ' => 'ĥ',
+ 'Ĩ' => 'Ĩ',
+ 'ĩ' => 'ĩ',
+ 'Ī' => 'Ī',
+ 'ī' => 'ī',
+ 'Ĭ' => 'Ĭ',
+ 'ĭ' => 'ĭ',
+ 'Į' => 'Į',
+ 'į' => 'į',
+ 'İ' => 'İ',
+ 'Ĵ' => 'Ĵ',
+ 'ĵ' => 'ĵ',
+ 'Ķ' => 'Ķ',
+ 'ķ' => 'ķ',
+ 'Ĺ' => 'Ĺ',
+ 'ĺ' => 'ĺ',
+ 'Ļ' => 'Ļ',
+ 'ļ' => 'ļ',
+ 'Ľ' => 'Ľ',
+ 'ľ' => 'ľ',
+ 'Ń' => 'Ń',
+ 'ń' => 'ń',
+ 'Ņ' => 'Ņ',
+ 'ņ' => 'ņ',
+ 'Ň' => 'Ň',
+ 'ň' => 'ň',
+ 'Ō' => 'Ō',
+ 'ō' => 'ō',
+ 'Ŏ' => 'Ŏ',
+ 'ŏ' => 'ŏ',
+ 'Ő' => 'Ő',
+ 'ő' => 'ő',
+ 'Ŕ' => 'Ŕ',
+ 'ŕ' => 'ŕ',
+ 'Ŗ' => 'Ŗ',
+ 'ŗ' => 'ŗ',
+ 'Ř' => 'Ř',
+ 'ř' => 'ř',
+ 'Ś' => 'Ś',
+ 'ś' => 'ś',
+ 'Ŝ' => 'Ŝ',
+ 'ŝ' => 'ŝ',
+ 'Ş' => 'Ş',
+ 'ş' => 'ş',
+ 'Š' => 'Š',
+ 'š' => 'š',
+ 'Ţ' => 'Ţ',
+ 'ţ' => 'ţ',
+ 'Ť' => 'Ť',
+ 'ť' => 'ť',
+ 'Ũ' => 'Ũ',
+ 'ũ' => 'ũ',
+ 'Ū' => 'Ū',
+ 'ū' => 'ū',
+ 'Ŭ' => 'Ŭ',
+ 'ŭ' => 'ŭ',
+ 'Ů' => 'Ů',
+ 'ů' => 'ů',
+ 'Ű' => 'Ű',
+ 'ű' => 'ű',
+ 'Ų' => 'Ų',
+ 'ų' => 'ų',
+ 'Ŵ' => 'Ŵ',
+ 'ŵ' => 'ŵ',
+ 'Ŷ' => 'Ŷ',
+ 'ŷ' => 'ŷ',
+ 'Ÿ' => 'Ÿ',
+ 'Ź' => 'Ź',
+ 'ź' => 'ź',
+ 'Ż' => 'Ż',
+ 'ż' => 'ż',
+ 'Ž' => 'Ž',
+ 'ž' => 'ž',
+ 'Ơ' => 'Ơ',
+ 'ơ' => 'ơ',
+ 'Ư' => 'Ư',
+ 'ư' => 'ư',
+ 'Ǎ' => 'Ǎ',
+ 'ǎ' => 'ǎ',
+ 'Ǐ' => 'Ǐ',
+ 'ǐ' => 'ǐ',
+ 'Ǒ' => 'Ǒ',
+ 'ǒ' => 'ǒ',
+ 'Ǔ' => 'Ǔ',
+ 'ǔ' => 'ǔ',
+ 'Ǖ' => 'Ǖ',
+ 'ǖ' => 'ǖ',
+ 'Ǘ' => 'Ǘ',
+ 'ǘ' => 'ǘ',
+ 'Ǚ' => 'Ǚ',
+ 'ǚ' => 'ǚ',
+ 'Ǜ' => 'Ǜ',
+ 'ǜ' => 'ǜ',
+ 'Ǟ' => 'Ǟ',
+ 'ǟ' => 'ǟ',
+ 'Ǡ' => 'Ǡ',
+ 'ǡ' => 'ǡ',
+ 'Ǣ' => 'Ǣ',
+ 'ǣ' => 'ǣ',
+ 'Ǧ' => 'Ǧ',
+ 'ǧ' => 'ǧ',
+ 'Ǩ' => 'Ǩ',
+ 'ǩ' => 'ǩ',
+ 'Ǫ' => 'Ǫ',
+ 'ǫ' => 'ǫ',
+ 'Ǭ' => 'Ǭ',
+ 'ǭ' => 'ǭ',
+ 'Ǯ' => 'Ǯ',
+ 'ǯ' => 'ǯ',
+ 'ǰ' => 'ǰ',
+ 'Ǵ' => 'Ǵ',
+ 'ǵ' => 'ǵ',
+ 'Ǹ' => 'Ǹ',
+ 'ǹ' => 'ǹ',
+ 'Ǻ' => 'Ǻ',
+ 'ǻ' => 'ǻ',
+ 'Ǽ' => 'Ǽ',
+ 'ǽ' => 'ǽ',
+ 'Ǿ' => 'Ǿ',
+ 'ǿ' => 'ǿ',
+ 'Ȁ' => 'Ȁ',
+ 'ȁ' => 'ȁ',
+ 'Ȃ' => 'Ȃ',
+ 'ȃ' => 'ȃ',
+ 'Ȅ' => 'Ȅ',
+ 'ȅ' => 'ȅ',
+ 'Ȇ' => 'Ȇ',
+ 'ȇ' => 'ȇ',
+ 'Ȉ' => 'Ȉ',
+ 'ȉ' => 'ȉ',
+ 'Ȋ' => 'Ȋ',
+ 'ȋ' => 'ȋ',
+ 'Ȍ' => 'Ȍ',
+ 'ȍ' => 'ȍ',
+ 'Ȏ' => 'Ȏ',
+ 'ȏ' => 'ȏ',
+ 'Ȑ' => 'Ȑ',
+ 'ȑ' => 'ȑ',
+ 'Ȓ' => 'Ȓ',
+ 'ȓ' => 'ȓ',
+ 'Ȕ' => 'Ȕ',
+ 'ȕ' => 'ȕ',
+ 'Ȗ' => 'Ȗ',
+ 'ȗ' => 'ȗ',
+ 'Ș' => 'Ș',
+ 'ș' => 'ș',
+ 'Ț' => 'Ț',
+ 'ț' => 'ț',
+ 'Ȟ' => 'Ȟ',
+ 'ȟ' => 'ȟ',
+ 'Ȧ' => 'Ȧ',
+ 'ȧ' => 'ȧ',
+ 'Ȩ' => 'Ȩ',
+ 'ȩ' => 'ȩ',
+ 'Ȫ' => 'Ȫ',
+ 'ȫ' => 'ȫ',
+ 'Ȭ' => 'Ȭ',
+ 'ȭ' => 'ȭ',
+ 'Ȯ' => 'Ȯ',
+ 'ȯ' => 'ȯ',
+ 'Ȱ' => 'Ȱ',
+ 'ȱ' => 'ȱ',
+ 'Ȳ' => 'Ȳ',
+ 'ȳ' => 'ȳ',
+ '΅' => '΅',
+ 'Ά' => 'Ά',
+ 'Έ' => 'Έ',
+ 'Ή' => 'Ή',
+ 'Ί' => 'Ί',
+ 'Ό' => 'Ό',
+ 'Ύ' => 'Ύ',
+ 'Ώ' => 'Ώ',
+ 'ΐ' => 'ΐ',
+ 'Ϊ' => 'Ϊ',
+ 'Ϋ' => 'Ϋ',
+ 'ά' => 'ά',
+ 'έ' => 'έ',
+ 'ή' => 'ή',
+ 'ί' => 'ί',
+ 'ΰ' => 'ΰ',
+ 'ϊ' => 'ϊ',
+ 'ϋ' => 'ϋ',
+ 'ό' => 'ό',
+ 'ύ' => 'ύ',
+ 'ώ' => 'ώ',
+ 'ϓ' => 'ϓ',
+ 'ϔ' => 'ϔ',
+ 'Ѐ' => 'Ѐ',
+ 'Ё' => 'Ё',
+ 'Ѓ' => 'Ѓ',
+ 'Ї' => 'Ї',
+ 'Ќ' => 'Ќ',
+ 'Ѝ' => 'Ѝ',
+ 'Ў' => 'Ў',
+ 'Й' => 'Й',
+ 'й' => 'й',
+ 'ѐ' => 'ѐ',
+ 'ё' => 'ё',
+ 'ѓ' => 'ѓ',
+ 'ї' => 'ї',
+ 'ќ' => 'ќ',
+ 'ѝ' => 'ѝ',
+ 'ў' => 'ў',
+ 'Ѷ' => 'Ѷ',
+ 'ѷ' => 'ѷ',
+ 'Ӂ' => 'Ӂ',
+ 'ӂ' => 'ӂ',
+ 'Ӑ' => 'Ӑ',
+ 'ӑ' => 'ӑ',
+ 'Ӓ' => 'Ӓ',
+ 'ӓ' => 'ӓ',
+ 'Ӗ' => 'Ӗ',
+ 'ӗ' => 'ӗ',
+ 'Ӛ' => 'Ӛ',
+ 'ӛ' => 'ӛ',
+ 'Ӝ' => 'Ӝ',
+ 'ӝ' => 'ӝ',
+ 'Ӟ' => 'Ӟ',
+ 'ӟ' => 'ӟ',
+ 'Ӣ' => 'Ӣ',
+ 'ӣ' => 'ӣ',
+ 'Ӥ' => 'Ӥ',
+ 'ӥ' => 'ӥ',
+ 'Ӧ' => 'Ӧ',
+ 'ӧ' => 'ӧ',
+ 'Ӫ' => 'Ӫ',
+ 'ӫ' => 'ӫ',
+ 'Ӭ' => 'Ӭ',
+ 'ӭ' => 'ӭ',
+ 'Ӯ' => 'Ӯ',
+ 'ӯ' => 'ӯ',
+ 'Ӱ' => 'Ӱ',
+ 'ӱ' => 'ӱ',
+ 'Ӳ' => 'Ӳ',
+ 'ӳ' => 'ӳ',
+ 'Ӵ' => 'Ӵ',
+ 'ӵ' => 'ӵ',
+ 'Ӹ' => 'Ӹ',
+ 'ӹ' => 'ӹ',
+ 'آ' => 'آ',
+ 'أ' => 'أ',
+ 'ؤ' => 'ؤ',
+ 'إ' => 'إ',
+ 'ئ' => 'ئ',
+ 'ۀ' => 'ۀ',
+ 'ۂ' => 'ۂ',
+ 'ۓ' => 'ۓ',
+ 'ऩ' => 'ऩ',
+ 'ऱ' => 'ऱ',
+ 'ऴ' => 'ऴ',
+ 'ো' => 'ো',
+ 'ৌ' => 'ৌ',
+ 'ୈ' => 'ୈ',
+ 'ୋ' => 'ୋ',
+ 'ୌ' => 'ୌ',
+ 'ஔ' => 'ஔ',
+ 'ொ' => 'ொ',
+ 'ோ' => 'ோ',
+ 'ௌ' => 'ௌ',
+ 'ై' => 'ై',
+ 'ೀ' => 'ೀ',
+ 'ೇ' => 'ೇ',
+ 'ೈ' => 'ೈ',
+ 'ೊ' => 'ೊ',
+ 'ೋ' => 'ೋ',
+ 'ൊ' => 'ൊ',
+ 'ോ' => 'ോ',
+ 'ൌ' => 'ൌ',
+ 'ේ' => 'ේ',
+ 'ො' => 'ො',
+ 'ෝ' => 'ෝ',
+ 'ෞ' => 'ෞ',
+ 'ဦ' => 'ဦ',
+ 'ᬆ' => 'ᬆ',
+ 'ᬈ' => 'ᬈ',
+ 'ᬊ' => 'ᬊ',
+ 'ᬌ' => 'ᬌ',
+ 'ᬎ' => 'ᬎ',
+ 'ᬒ' => 'ᬒ',
+ 'ᬻ' => 'ᬻ',
+ 'ᬽ' => 'ᬽ',
+ 'ᭀ' => 'ᭀ',
+ 'ᭁ' => 'ᭁ',
+ 'ᭃ' => 'ᭃ',
+ 'Ḁ' => 'Ḁ',
+ 'ḁ' => 'ḁ',
+ 'Ḃ' => 'Ḃ',
+ 'ḃ' => 'ḃ',
+ 'Ḅ' => 'Ḅ',
+ 'ḅ' => 'ḅ',
+ 'Ḇ' => 'Ḇ',
+ 'ḇ' => 'ḇ',
+ 'Ḉ' => 'Ḉ',
+ 'ḉ' => 'ḉ',
+ 'Ḋ' => 'Ḋ',
+ 'ḋ' => 'ḋ',
+ 'Ḍ' => 'Ḍ',
+ 'ḍ' => 'ḍ',
+ 'Ḏ' => 'Ḏ',
+ 'ḏ' => 'ḏ',
+ 'Ḑ' => 'Ḑ',
+ 'ḑ' => 'ḑ',
+ 'Ḓ' => 'Ḓ',
+ 'ḓ' => 'ḓ',
+ 'Ḕ' => 'Ḕ',
+ 'ḕ' => 'ḕ',
+ 'Ḗ' => 'Ḗ',
+ 'ḗ' => 'ḗ',
+ 'Ḙ' => 'Ḙ',
+ 'ḙ' => 'ḙ',
+ 'Ḛ' => 'Ḛ',
+ 'ḛ' => 'ḛ',
+ 'Ḝ' => 'Ḝ',
+ 'ḝ' => 'ḝ',
+ 'Ḟ' => 'Ḟ',
+ 'ḟ' => 'ḟ',
+ 'Ḡ' => 'Ḡ',
+ 'ḡ' => 'ḡ',
+ 'Ḣ' => 'Ḣ',
+ 'ḣ' => 'ḣ',
+ 'Ḥ' => 'Ḥ',
+ 'ḥ' => 'ḥ',
+ 'Ḧ' => 'Ḧ',
+ 'ḧ' => 'ḧ',
+ 'Ḩ' => 'Ḩ',
+ 'ḩ' => 'ḩ',
+ 'Ḫ' => 'Ḫ',
+ 'ḫ' => 'ḫ',
+ 'Ḭ' => 'Ḭ',
+ 'ḭ' => 'ḭ',
+ 'Ḯ' => 'Ḯ',
+ 'ḯ' => 'ḯ',
+ 'Ḱ' => 'Ḱ',
+ 'ḱ' => 'ḱ',
+ 'Ḳ' => 'Ḳ',
+ 'ḳ' => 'ḳ',
+ 'Ḵ' => 'Ḵ',
+ 'ḵ' => 'ḵ',
+ 'Ḷ' => 'Ḷ',
+ 'ḷ' => 'ḷ',
+ 'Ḹ' => 'Ḹ',
+ 'ḹ' => 'ḹ',
+ 'Ḻ' => 'Ḻ',
+ 'ḻ' => 'ḻ',
+ 'Ḽ' => 'Ḽ',
+ 'ḽ' => 'ḽ',
+ 'Ḿ' => 'Ḿ',
+ 'ḿ' => 'ḿ',
+ 'Ṁ' => 'Ṁ',
+ 'ṁ' => 'ṁ',
+ 'Ṃ' => 'Ṃ',
+ 'ṃ' => 'ṃ',
+ 'Ṅ' => 'Ṅ',
+ 'ṅ' => 'ṅ',
+ 'Ṇ' => 'Ṇ',
+ 'ṇ' => 'ṇ',
+ 'Ṉ' => 'Ṉ',
+ 'ṉ' => 'ṉ',
+ 'Ṋ' => 'Ṋ',
+ 'ṋ' => 'ṋ',
+ 'Ṍ' => 'Ṍ',
+ 'ṍ' => 'ṍ',
+ 'Ṏ' => 'Ṏ',
+ 'ṏ' => 'ṏ',
+ 'Ṑ' => 'Ṑ',
+ 'ṑ' => 'ṑ',
+ 'Ṓ' => 'Ṓ',
+ 'ṓ' => 'ṓ',
+ 'Ṕ' => 'Ṕ',
+ 'ṕ' => 'ṕ',
+ 'Ṗ' => 'Ṗ',
+ 'ṗ' => 'ṗ',
+ 'Ṙ' => 'Ṙ',
+ 'ṙ' => 'ṙ',
+ 'Ṛ' => 'Ṛ',
+ 'ṛ' => 'ṛ',
+ 'Ṝ' => 'Ṝ',
+ 'ṝ' => 'ṝ',
+ 'Ṟ' => 'Ṟ',
+ 'ṟ' => 'ṟ',
+ 'Ṡ' => 'Ṡ',
+ 'ṡ' => 'ṡ',
+ 'Ṣ' => 'Ṣ',
+ 'ṣ' => 'ṣ',
+ 'Ṥ' => 'Ṥ',
+ 'ṥ' => 'ṥ',
+ 'Ṧ' => 'Ṧ',
+ 'ṧ' => 'ṧ',
+ 'Ṩ' => 'Ṩ',
+ 'ṩ' => 'ṩ',
+ 'Ṫ' => 'Ṫ',
+ 'ṫ' => 'ṫ',
+ 'Ṭ' => 'Ṭ',
+ 'ṭ' => 'ṭ',
+ 'Ṯ' => 'Ṯ',
+ 'ṯ' => 'ṯ',
+ 'Ṱ' => 'Ṱ',
+ 'ṱ' => 'ṱ',
+ 'Ṳ' => 'Ṳ',
+ 'ṳ' => 'ṳ',
+ 'Ṵ' => 'Ṵ',
+ 'ṵ' => 'ṵ',
+ 'Ṷ' => 'Ṷ',
+ 'ṷ' => 'ṷ',
+ 'Ṹ' => 'Ṹ',
+ 'ṹ' => 'ṹ',
+ 'Ṻ' => 'Ṻ',
+ 'ṻ' => 'ṻ',
+ 'Ṽ' => 'Ṽ',
+ 'ṽ' => 'ṽ',
+ 'Ṿ' => 'Ṿ',
+ 'ṿ' => 'ṿ',
+ 'Ẁ' => 'Ẁ',
+ 'ẁ' => 'ẁ',
+ 'Ẃ' => 'Ẃ',
+ 'ẃ' => 'ẃ',
+ 'Ẅ' => 'Ẅ',
+ 'ẅ' => 'ẅ',
+ 'Ẇ' => 'Ẇ',
+ 'ẇ' => 'ẇ',
+ 'Ẉ' => 'Ẉ',
+ 'ẉ' => 'ẉ',
+ 'Ẋ' => 'Ẋ',
+ 'ẋ' => 'ẋ',
+ 'Ẍ' => 'Ẍ',
+ 'ẍ' => 'ẍ',
+ 'Ẏ' => 'Ẏ',
+ 'ẏ' => 'ẏ',
+ 'Ẑ' => 'Ẑ',
+ 'ẑ' => 'ẑ',
+ 'Ẓ' => 'Ẓ',
+ 'ẓ' => 'ẓ',
+ 'Ẕ' => 'Ẕ',
+ 'ẕ' => 'ẕ',
+ 'ẖ' => 'ẖ',
+ 'ẗ' => 'ẗ',
+ 'ẘ' => 'ẘ',
+ 'ẙ' => 'ẙ',
+ 'ẛ' => 'ẛ',
+ 'Ạ' => 'Ạ',
+ 'ạ' => 'ạ',
+ 'Ả' => 'Ả',
+ 'ả' => 'ả',
+ 'Ấ' => 'Ấ',
+ 'ấ' => 'ấ',
+ 'Ầ' => 'Ầ',
+ 'ầ' => 'ầ',
+ 'Ẩ' => 'Ẩ',
+ 'ẩ' => 'ẩ',
+ 'Ẫ' => 'Ẫ',
+ 'ẫ' => 'ẫ',
+ 'Ậ' => 'Ậ',
+ 'ậ' => 'ậ',
+ 'Ắ' => 'Ắ',
+ 'ắ' => 'ắ',
+ 'Ằ' => 'Ằ',
+ 'ằ' => 'ằ',
+ 'Ẳ' => 'Ẳ',
+ 'ẳ' => 'ẳ',
+ 'Ẵ' => 'Ẵ',
+ 'ẵ' => 'ẵ',
+ 'Ặ' => 'Ặ',
+ 'ặ' => 'ặ',
+ 'Ẹ' => 'Ẹ',
+ 'ẹ' => 'ẹ',
+ 'Ẻ' => 'Ẻ',
+ 'ẻ' => 'ẻ',
+ 'Ẽ' => 'Ẽ',
+ 'ẽ' => 'ẽ',
+ 'Ế' => 'Ế',
+ 'ế' => 'ế',
+ 'Ề' => 'Ề',
+ 'ề' => 'ề',
+ 'Ể' => 'Ể',
+ 'ể' => 'ể',
+ 'Ễ' => 'Ễ',
+ 'ễ' => 'ễ',
+ 'Ệ' => 'Ệ',
+ 'ệ' => 'ệ',
+ 'Ỉ' => 'Ỉ',
+ 'ỉ' => 'ỉ',
+ 'Ị' => 'Ị',
+ 'ị' => 'ị',
+ 'Ọ' => 'Ọ',
+ 'ọ' => 'ọ',
+ 'Ỏ' => 'Ỏ',
+ 'ỏ' => 'ỏ',
+ 'Ố' => 'Ố',
+ 'ố' => 'ố',
+ 'Ồ' => 'Ồ',
+ 'ồ' => 'ồ',
+ 'Ổ' => 'Ổ',
+ 'ổ' => 'ổ',
+ 'Ỗ' => 'Ỗ',
+ 'ỗ' => 'ỗ',
+ 'Ộ' => 'Ộ',
+ 'ộ' => 'ộ',
+ 'Ớ' => 'Ớ',
+ 'ớ' => 'ớ',
+ 'Ờ' => 'Ờ',
+ 'ờ' => 'ờ',
+ 'Ở' => 'Ở',
+ 'ở' => 'ở',
+ 'Ỡ' => 'Ỡ',
+ 'ỡ' => 'ỡ',
+ 'Ợ' => 'Ợ',
+ 'ợ' => 'ợ',
+ 'Ụ' => 'Ụ',
+ 'ụ' => 'ụ',
+ 'Ủ' => 'Ủ',
+ 'ủ' => 'ủ',
+ 'Ứ' => 'Ứ',
+ 'ứ' => 'ứ',
+ 'Ừ' => 'Ừ',
+ 'ừ' => 'ừ',
+ 'Ử' => 'Ử',
+ 'ử' => 'ử',
+ 'Ữ' => 'Ữ',
+ 'ữ' => 'ữ',
+ 'Ự' => 'Ự',
+ 'ự' => 'ự',
+ 'Ỳ' => 'Ỳ',
+ 'ỳ' => 'ỳ',
+ 'Ỵ' => 'Ỵ',
+ 'ỵ' => 'ỵ',
+ 'Ỷ' => 'Ỷ',
+ 'ỷ' => 'ỷ',
+ 'Ỹ' => 'Ỹ',
+ 'ỹ' => 'ỹ',
+ 'ἀ' => 'ἀ',
+ 'ἁ' => 'ἁ',
+ 'ἂ' => 'ἂ',
+ 'ἃ' => 'ἃ',
+ 'ἄ' => 'ἄ',
+ 'ἅ' => 'ἅ',
+ 'ἆ' => 'ἆ',
+ 'ἇ' => 'ἇ',
+ 'Ἀ' => 'Ἀ',
+ 'Ἁ' => 'Ἁ',
+ 'Ἂ' => 'Ἂ',
+ 'Ἃ' => 'Ἃ',
+ 'Ἄ' => 'Ἄ',
+ 'Ἅ' => 'Ἅ',
+ 'Ἆ' => 'Ἆ',
+ 'Ἇ' => 'Ἇ',
+ 'ἐ' => 'ἐ',
+ 'ἑ' => 'ἑ',
+ 'ἒ' => 'ἒ',
+ 'ἓ' => 'ἓ',
+ 'ἔ' => 'ἔ',
+ 'ἕ' => 'ἕ',
+ 'Ἐ' => 'Ἐ',
+ 'Ἑ' => 'Ἑ',
+ 'Ἒ' => 'Ἒ',
+ 'Ἓ' => 'Ἓ',
+ 'Ἔ' => 'Ἔ',
+ 'Ἕ' => 'Ἕ',
+ 'ἠ' => 'ἠ',
+ 'ἡ' => 'ἡ',
+ 'ἢ' => 'ἢ',
+ 'ἣ' => 'ἣ',
+ 'ἤ' => 'ἤ',
+ 'ἥ' => 'ἥ',
+ 'ἦ' => 'ἦ',
+ 'ἧ' => 'ἧ',
+ 'Ἠ' => 'Ἠ',
+ 'Ἡ' => 'Ἡ',
+ 'Ἢ' => 'Ἢ',
+ 'Ἣ' => 'Ἣ',
+ 'Ἤ' => 'Ἤ',
+ 'Ἥ' => 'Ἥ',
+ 'Ἦ' => 'Ἦ',
+ 'Ἧ' => 'Ἧ',
+ 'ἰ' => 'ἰ',
+ 'ἱ' => 'ἱ',
+ 'ἲ' => 'ἲ',
+ 'ἳ' => 'ἳ',
+ 'ἴ' => 'ἴ',
+ 'ἵ' => 'ἵ',
+ 'ἶ' => 'ἶ',
+ 'ἷ' => 'ἷ',
+ 'Ἰ' => 'Ἰ',
+ 'Ἱ' => 'Ἱ',
+ 'Ἲ' => 'Ἲ',
+ 'Ἳ' => 'Ἳ',
+ 'Ἴ' => 'Ἴ',
+ 'Ἵ' => 'Ἵ',
+ 'Ἶ' => 'Ἶ',
+ 'Ἷ' => 'Ἷ',
+ 'ὀ' => 'ὀ',
+ 'ὁ' => 'ὁ',
+ 'ὂ' => 'ὂ',
+ 'ὃ' => 'ὃ',
+ 'ὄ' => 'ὄ',
+ 'ὅ' => 'ὅ',
+ 'Ὀ' => 'Ὀ',
+ 'Ὁ' => 'Ὁ',
+ 'Ὂ' => 'Ὂ',
+ 'Ὃ' => 'Ὃ',
+ 'Ὄ' => 'Ὄ',
+ 'Ὅ' => 'Ὅ',
+ 'ὐ' => 'ὐ',
+ 'ὑ' => 'ὑ',
+ 'ὒ' => 'ὒ',
+ 'ὓ' => 'ὓ',
+ 'ὔ' => 'ὔ',
+ 'ὕ' => 'ὕ',
+ 'ὖ' => 'ὖ',
+ 'ὗ' => 'ὗ',
+ 'Ὑ' => 'Ὑ',
+ 'Ὓ' => 'Ὓ',
+ 'Ὕ' => 'Ὕ',
+ 'Ὗ' => 'Ὗ',
+ 'ὠ' => 'ὠ',
+ 'ὡ' => 'ὡ',
+ 'ὢ' => 'ὢ',
+ 'ὣ' => 'ὣ',
+ 'ὤ' => 'ὤ',
+ 'ὥ' => 'ὥ',
+ 'ὦ' => 'ὦ',
+ 'ὧ' => 'ὧ',
+ 'Ὠ' => 'Ὠ',
+ 'Ὡ' => 'Ὡ',
+ 'Ὢ' => 'Ὢ',
+ 'Ὣ' => 'Ὣ',
+ 'Ὤ' => 'Ὤ',
+ 'Ὥ' => 'Ὥ',
+ 'Ὦ' => 'Ὦ',
+ 'Ὧ' => 'Ὧ',
+ 'ὰ' => 'ὰ',
+ 'ὲ' => 'ὲ',
+ 'ὴ' => 'ὴ',
+ 'ὶ' => 'ὶ',
+ 'ὸ' => 'ὸ',
+ 'ὺ' => 'ὺ',
+ 'ὼ' => 'ὼ',
+ 'ᾀ' => 'ᾀ',
+ 'ᾁ' => 'ᾁ',
+ 'ᾂ' => 'ᾂ',
+ 'ᾃ' => 'ᾃ',
+ 'ᾄ' => 'ᾄ',
+ 'ᾅ' => 'ᾅ',
+ 'ᾆ' => 'ᾆ',
+ 'ᾇ' => 'ᾇ',
+ 'ᾈ' => 'ᾈ',
+ 'ᾉ' => 'ᾉ',
+ 'ᾊ' => 'ᾊ',
+ 'ᾋ' => 'ᾋ',
+ 'ᾌ' => 'ᾌ',
+ 'ᾍ' => 'ᾍ',
+ 'ᾎ' => 'ᾎ',
+ 'ᾏ' => 'ᾏ',
+ 'ᾐ' => 'ᾐ',
+ 'ᾑ' => 'ᾑ',
+ 'ᾒ' => 'ᾒ',
+ 'ᾓ' => 'ᾓ',
+ 'ᾔ' => 'ᾔ',
+ 'ᾕ' => 'ᾕ',
+ 'ᾖ' => 'ᾖ',
+ 'ᾗ' => 'ᾗ',
+ 'ᾘ' => 'ᾘ',
+ 'ᾙ' => 'ᾙ',
+ 'ᾚ' => 'ᾚ',
+ 'ᾛ' => 'ᾛ',
+ 'ᾜ' => 'ᾜ',
+ 'ᾝ' => 'ᾝ',
+ 'ᾞ' => 'ᾞ',
+ 'ᾟ' => 'ᾟ',
+ 'ᾠ' => 'ᾠ',
+ 'ᾡ' => 'ᾡ',
+ 'ᾢ' => 'ᾢ',
+ 'ᾣ' => 'ᾣ',
+ 'ᾤ' => 'ᾤ',
+ 'ᾥ' => 'ᾥ',
+ 'ᾦ' => 'ᾦ',
+ 'ᾧ' => 'ᾧ',
+ 'ᾨ' => 'ᾨ',
+ 'ᾩ' => 'ᾩ',
+ 'ᾪ' => 'ᾪ',
+ 'ᾫ' => 'ᾫ',
+ 'ᾬ' => 'ᾬ',
+ 'ᾭ' => 'ᾭ',
+ 'ᾮ' => 'ᾮ',
+ 'ᾯ' => 'ᾯ',
+ 'ᾰ' => 'ᾰ',
+ 'ᾱ' => 'ᾱ',
+ 'ᾲ' => 'ᾲ',
+ 'ᾳ' => 'ᾳ',
+ 'ᾴ' => 'ᾴ',
+ 'ᾶ' => 'ᾶ',
+ 'ᾷ' => 'ᾷ',
+ 'Ᾰ' => 'Ᾰ',
+ 'Ᾱ' => 'Ᾱ',
+ 'Ὰ' => 'Ὰ',
+ 'ᾼ' => 'ᾼ',
+ '῁' => '῁',
+ 'ῂ' => 'ῂ',
+ 'ῃ' => 'ῃ',
+ 'ῄ' => 'ῄ',
+ 'ῆ' => 'ῆ',
+ 'ῇ' => 'ῇ',
+ 'Ὲ' => 'Ὲ',
+ 'Ὴ' => 'Ὴ',
+ 'ῌ' => 'ῌ',
+ '῍' => '῍',
+ '῎' => '῎',
+ '῏' => '῏',
+ 'ῐ' => 'ῐ',
+ 'ῑ' => 'ῑ',
+ 'ῒ' => 'ῒ',
+ 'ῖ' => 'ῖ',
+ 'ῗ' => 'ῗ',
+ 'Ῐ' => 'Ῐ',
+ 'Ῑ' => 'Ῑ',
+ 'Ὶ' => 'Ὶ',
+ '῝' => '῝',
+ '῞' => '῞',
+ '῟' => '῟',
+ 'ῠ' => 'ῠ',
+ 'ῡ' => 'ῡ',
+ 'ῢ' => 'ῢ',
+ 'ῤ' => 'ῤ',
+ 'ῥ' => 'ῥ',
+ 'ῦ' => 'ῦ',
+ 'ῧ' => 'ῧ',
+ 'Ῠ' => 'Ῠ',
+ 'Ῡ' => 'Ῡ',
+ 'Ὺ' => 'Ὺ',
+ 'Ῥ' => 'Ῥ',
+ '῭' => '῭',
+ 'ῲ' => 'ῲ',
+ 'ῳ' => 'ῳ',
+ 'ῴ' => 'ῴ',
+ 'ῶ' => 'ῶ',
+ 'ῷ' => 'ῷ',
+ 'Ὸ' => 'Ὸ',
+ 'Ὼ' => 'Ὼ',
+ 'ῼ' => 'ῼ',
+ '↚' => '↚',
+ '↛' => '↛',
+ '↮' => '↮',
+ '⇍' => '⇍',
+ '⇎' => '⇎',
+ '⇏' => '⇏',
+ '∄' => '∄',
+ '∉' => '∉',
+ '∌' => '∌',
+ '∤' => '∤',
+ '∦' => '∦',
+ '≁' => '≁',
+ '≄' => '≄',
+ '≇' => '≇',
+ '≉' => '≉',
+ '≠' => '≠',
+ '≢' => '≢',
+ '≭' => '≭',
+ '≮' => '≮',
+ '≯' => '≯',
+ '≰' => '≰',
+ '≱' => '≱',
+ '≴' => '≴',
+ '≵' => '≵',
+ '≸' => '≸',
+ '≹' => '≹',
+ '⊀' => '⊀',
+ '⊁' => '⊁',
+ '⊄' => '⊄',
+ '⊅' => '⊅',
+ '⊈' => '⊈',
+ '⊉' => '⊉',
+ '⊬' => '⊬',
+ '⊭' => '⊭',
+ '⊮' => '⊮',
+ '⊯' => '⊯',
+ '⋠' => '⋠',
+ '⋡' => '⋡',
+ '⋢' => '⋢',
+ '⋣' => '⋣',
+ '⋪' => '⋪',
+ '⋫' => '⋫',
+ '⋬' => '⋬',
+ '⋭' => '⋭',
+ 'が' => 'が',
+ 'ぎ' => 'ぎ',
+ 'ぐ' => 'ぐ',
+ 'げ' => 'げ',
+ 'ご' => 'ご',
+ 'ざ' => 'ざ',
+ 'じ' => 'じ',
+ 'ず' => 'ず',
+ 'ぜ' => 'ぜ',
+ 'ぞ' => 'ぞ',
+ 'だ' => 'だ',
+ 'ぢ' => 'ぢ',
+ 'づ' => 'づ',
+ 'で' => 'で',
+ 'ど' => 'ど',
+ 'ば' => 'ば',
+ 'ぱ' => 'ぱ',
+ 'び' => 'び',
+ 'ぴ' => 'ぴ',
+ 'ぶ' => 'ぶ',
+ 'ぷ' => 'ぷ',
+ 'べ' => 'べ',
+ 'ぺ' => 'ぺ',
+ 'ぼ' => 'ぼ',
+ 'ぽ' => 'ぽ',
+ 'ゔ' => 'ゔ',
+ 'ゞ' => 'ゞ',
+ 'ガ' => 'ガ',
+ 'ギ' => 'ギ',
+ 'グ' => 'グ',
+ 'ゲ' => 'ゲ',
+ 'ゴ' => 'ゴ',
+ 'ザ' => 'ザ',
+ 'ジ' => 'ジ',
+ 'ズ' => 'ズ',
+ 'ゼ' => 'ゼ',
+ 'ゾ' => 'ゾ',
+ 'ダ' => 'ダ',
+ 'ヂ' => 'ヂ',
+ 'ヅ' => 'ヅ',
+ 'デ' => 'デ',
+ 'ド' => 'ド',
+ 'バ' => 'バ',
+ 'パ' => 'パ',
+ 'ビ' => 'ビ',
+ 'ピ' => 'ピ',
+ 'ブ' => 'ブ',
+ 'プ' => 'プ',
+ 'ベ' => 'ベ',
+ 'ペ' => 'ペ',
+ 'ボ' => 'ボ',
+ 'ポ' => 'ポ',
+ 'ヴ' => 'ヴ',
+ 'ヷ' => 'ヷ',
+ 'ヸ' => 'ヸ',
+ 'ヹ' => 'ヹ',
+ 'ヺ' => 'ヺ',
+ 'ヾ' => 'ヾ',
+ '𑂚' => '𑂚',
+ '𑂜' => '𑂜',
+ '𑂫' => '𑂫',
+ '𑄮' => '𑄮',
+ '𑄯' => '𑄯',
+ '𑍋' => '𑍋',
+ '𑍌' => '𑍌',
+ '𑒻' => '𑒻',
+ '𑒼' => '𑒼',
+ '𑒾' => '𑒾',
+ '𑖺' => '𑖺',
+ '𑖻' => '𑖻',
+ '𑤸' => '𑤸',
+);
diff --git a/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php b/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php
new file mode 100644
index 000000000..5a3e8e096
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php
@@ -0,0 +1,2065 @@
+ 'À',
+ 'Á' => 'Á',
+ 'Â' => 'Â',
+ 'Ã' => 'Ã',
+ 'Ä' => 'Ä',
+ 'Å' => 'Å',
+ 'Ç' => 'Ç',
+ 'È' => 'È',
+ 'É' => 'É',
+ 'Ê' => 'Ê',
+ 'Ë' => 'Ë',
+ 'Ì' => 'Ì',
+ 'Í' => 'Í',
+ 'Î' => 'Î',
+ 'Ï' => 'Ï',
+ 'Ñ' => 'Ñ',
+ 'Ò' => 'Ò',
+ 'Ó' => 'Ó',
+ 'Ô' => 'Ô',
+ 'Õ' => 'Õ',
+ 'Ö' => 'Ö',
+ 'Ù' => 'Ù',
+ 'Ú' => 'Ú',
+ 'Û' => 'Û',
+ 'Ü' => 'Ü',
+ 'Ý' => 'Ý',
+ 'à' => 'à',
+ 'á' => 'á',
+ 'â' => 'â',
+ 'ã' => 'ã',
+ 'ä' => 'ä',
+ 'å' => 'å',
+ 'ç' => 'ç',
+ 'è' => 'è',
+ 'é' => 'é',
+ 'ê' => 'ê',
+ 'ë' => 'ë',
+ 'ì' => 'ì',
+ 'í' => 'í',
+ 'î' => 'î',
+ 'ï' => 'ï',
+ 'ñ' => 'ñ',
+ 'ò' => 'ò',
+ 'ó' => 'ó',
+ 'ô' => 'ô',
+ 'õ' => 'õ',
+ 'ö' => 'ö',
+ 'ù' => 'ù',
+ 'ú' => 'ú',
+ 'û' => 'û',
+ 'ü' => 'ü',
+ 'ý' => 'ý',
+ 'ÿ' => 'ÿ',
+ 'Ā' => 'Ā',
+ 'ā' => 'ā',
+ 'Ă' => 'Ă',
+ 'ă' => 'ă',
+ 'Ą' => 'Ą',
+ 'ą' => 'ą',
+ 'Ć' => 'Ć',
+ 'ć' => 'ć',
+ 'Ĉ' => 'Ĉ',
+ 'ĉ' => 'ĉ',
+ 'Ċ' => 'Ċ',
+ 'ċ' => 'ċ',
+ 'Č' => 'Č',
+ 'č' => 'č',
+ 'Ď' => 'Ď',
+ 'ď' => 'ď',
+ 'Ē' => 'Ē',
+ 'ē' => 'ē',
+ 'Ĕ' => 'Ĕ',
+ 'ĕ' => 'ĕ',
+ 'Ė' => 'Ė',
+ 'ė' => 'ė',
+ 'Ę' => 'Ę',
+ 'ę' => 'ę',
+ 'Ě' => 'Ě',
+ 'ě' => 'ě',
+ 'Ĝ' => 'Ĝ',
+ 'ĝ' => 'ĝ',
+ 'Ğ' => 'Ğ',
+ 'ğ' => 'ğ',
+ 'Ġ' => 'Ġ',
+ 'ġ' => 'ġ',
+ 'Ģ' => 'Ģ',
+ 'ģ' => 'ģ',
+ 'Ĥ' => 'Ĥ',
+ 'ĥ' => 'ĥ',
+ 'Ĩ' => 'Ĩ',
+ 'ĩ' => 'ĩ',
+ 'Ī' => 'Ī',
+ 'ī' => 'ī',
+ 'Ĭ' => 'Ĭ',
+ 'ĭ' => 'ĭ',
+ 'Į' => 'Į',
+ 'į' => 'į',
+ 'İ' => 'İ',
+ 'Ĵ' => 'Ĵ',
+ 'ĵ' => 'ĵ',
+ 'Ķ' => 'Ķ',
+ 'ķ' => 'ķ',
+ 'Ĺ' => 'Ĺ',
+ 'ĺ' => 'ĺ',
+ 'Ļ' => 'Ļ',
+ 'ļ' => 'ļ',
+ 'Ľ' => 'Ľ',
+ 'ľ' => 'ľ',
+ 'Ń' => 'Ń',
+ 'ń' => 'ń',
+ 'Ņ' => 'Ņ',
+ 'ņ' => 'ņ',
+ 'Ň' => 'Ň',
+ 'ň' => 'ň',
+ 'Ō' => 'Ō',
+ 'ō' => 'ō',
+ 'Ŏ' => 'Ŏ',
+ 'ŏ' => 'ŏ',
+ 'Ő' => 'Ő',
+ 'ő' => 'ő',
+ 'Ŕ' => 'Ŕ',
+ 'ŕ' => 'ŕ',
+ 'Ŗ' => 'Ŗ',
+ 'ŗ' => 'ŗ',
+ 'Ř' => 'Ř',
+ 'ř' => 'ř',
+ 'Ś' => 'Ś',
+ 'ś' => 'ś',
+ 'Ŝ' => 'Ŝ',
+ 'ŝ' => 'ŝ',
+ 'Ş' => 'Ş',
+ 'ş' => 'ş',
+ 'Š' => 'Š',
+ 'š' => 'š',
+ 'Ţ' => 'Ţ',
+ 'ţ' => 'ţ',
+ 'Ť' => 'Ť',
+ 'ť' => 'ť',
+ 'Ũ' => 'Ũ',
+ 'ũ' => 'ũ',
+ 'Ū' => 'Ū',
+ 'ū' => 'ū',
+ 'Ŭ' => 'Ŭ',
+ 'ŭ' => 'ŭ',
+ 'Ů' => 'Ů',
+ 'ů' => 'ů',
+ 'Ű' => 'Ű',
+ 'ű' => 'ű',
+ 'Ų' => 'Ų',
+ 'ų' => 'ų',
+ 'Ŵ' => 'Ŵ',
+ 'ŵ' => 'ŵ',
+ 'Ŷ' => 'Ŷ',
+ 'ŷ' => 'ŷ',
+ 'Ÿ' => 'Ÿ',
+ 'Ź' => 'Ź',
+ 'ź' => 'ź',
+ 'Ż' => 'Ż',
+ 'ż' => 'ż',
+ 'Ž' => 'Ž',
+ 'ž' => 'ž',
+ 'Ơ' => 'Ơ',
+ 'ơ' => 'ơ',
+ 'Ư' => 'Ư',
+ 'ư' => 'ư',
+ 'Ǎ' => 'Ǎ',
+ 'ǎ' => 'ǎ',
+ 'Ǐ' => 'Ǐ',
+ 'ǐ' => 'ǐ',
+ 'Ǒ' => 'Ǒ',
+ 'ǒ' => 'ǒ',
+ 'Ǔ' => 'Ǔ',
+ 'ǔ' => 'ǔ',
+ 'Ǖ' => 'Ǖ',
+ 'ǖ' => 'ǖ',
+ 'Ǘ' => 'Ǘ',
+ 'ǘ' => 'ǘ',
+ 'Ǚ' => 'Ǚ',
+ 'ǚ' => 'ǚ',
+ 'Ǜ' => 'Ǜ',
+ 'ǜ' => 'ǜ',
+ 'Ǟ' => 'Ǟ',
+ 'ǟ' => 'ǟ',
+ 'Ǡ' => 'Ǡ',
+ 'ǡ' => 'ǡ',
+ 'Ǣ' => 'Ǣ',
+ 'ǣ' => 'ǣ',
+ 'Ǧ' => 'Ǧ',
+ 'ǧ' => 'ǧ',
+ 'Ǩ' => 'Ǩ',
+ 'ǩ' => 'ǩ',
+ 'Ǫ' => 'Ǫ',
+ 'ǫ' => 'ǫ',
+ 'Ǭ' => 'Ǭ',
+ 'ǭ' => 'ǭ',
+ 'Ǯ' => 'Ǯ',
+ 'ǯ' => 'ǯ',
+ 'ǰ' => 'ǰ',
+ 'Ǵ' => 'Ǵ',
+ 'ǵ' => 'ǵ',
+ 'Ǹ' => 'Ǹ',
+ 'ǹ' => 'ǹ',
+ 'Ǻ' => 'Ǻ',
+ 'ǻ' => 'ǻ',
+ 'Ǽ' => 'Ǽ',
+ 'ǽ' => 'ǽ',
+ 'Ǿ' => 'Ǿ',
+ 'ǿ' => 'ǿ',
+ 'Ȁ' => 'Ȁ',
+ 'ȁ' => 'ȁ',
+ 'Ȃ' => 'Ȃ',
+ 'ȃ' => 'ȃ',
+ 'Ȅ' => 'Ȅ',
+ 'ȅ' => 'ȅ',
+ 'Ȇ' => 'Ȇ',
+ 'ȇ' => 'ȇ',
+ 'Ȉ' => 'Ȉ',
+ 'ȉ' => 'ȉ',
+ 'Ȋ' => 'Ȋ',
+ 'ȋ' => 'ȋ',
+ 'Ȍ' => 'Ȍ',
+ 'ȍ' => 'ȍ',
+ 'Ȏ' => 'Ȏ',
+ 'ȏ' => 'ȏ',
+ 'Ȑ' => 'Ȑ',
+ 'ȑ' => 'ȑ',
+ 'Ȓ' => 'Ȓ',
+ 'ȓ' => 'ȓ',
+ 'Ȕ' => 'Ȕ',
+ 'ȕ' => 'ȕ',
+ 'Ȗ' => 'Ȗ',
+ 'ȗ' => 'ȗ',
+ 'Ș' => 'Ș',
+ 'ș' => 'ș',
+ 'Ț' => 'Ț',
+ 'ț' => 'ț',
+ 'Ȟ' => 'Ȟ',
+ 'ȟ' => 'ȟ',
+ 'Ȧ' => 'Ȧ',
+ 'ȧ' => 'ȧ',
+ 'Ȩ' => 'Ȩ',
+ 'ȩ' => 'ȩ',
+ 'Ȫ' => 'Ȫ',
+ 'ȫ' => 'ȫ',
+ 'Ȭ' => 'Ȭ',
+ 'ȭ' => 'ȭ',
+ 'Ȯ' => 'Ȯ',
+ 'ȯ' => 'ȯ',
+ 'Ȱ' => 'Ȱ',
+ 'ȱ' => 'ȱ',
+ 'Ȳ' => 'Ȳ',
+ 'ȳ' => 'ȳ',
+ '̀' => '̀',
+ '́' => '́',
+ '̓' => '̓',
+ '̈́' => '̈́',
+ 'ʹ' => 'ʹ',
+ ';' => ';',
+ '΅' => '΅',
+ 'Ά' => 'Ά',
+ '·' => '·',
+ 'Έ' => 'Έ',
+ 'Ή' => 'Ή',
+ 'Ί' => 'Ί',
+ 'Ό' => 'Ό',
+ 'Ύ' => 'Ύ',
+ 'Ώ' => 'Ώ',
+ 'ΐ' => 'ΐ',
+ 'Ϊ' => 'Ϊ',
+ 'Ϋ' => 'Ϋ',
+ 'ά' => 'ά',
+ 'έ' => 'έ',
+ 'ή' => 'ή',
+ 'ί' => 'ί',
+ 'ΰ' => 'ΰ',
+ 'ϊ' => 'ϊ',
+ 'ϋ' => 'ϋ',
+ 'ό' => 'ό',
+ 'ύ' => 'ύ',
+ 'ώ' => 'ώ',
+ 'ϓ' => 'ϓ',
+ 'ϔ' => 'ϔ',
+ 'Ѐ' => 'Ѐ',
+ 'Ё' => 'Ё',
+ 'Ѓ' => 'Ѓ',
+ 'Ї' => 'Ї',
+ 'Ќ' => 'Ќ',
+ 'Ѝ' => 'Ѝ',
+ 'Ў' => 'Ў',
+ 'Й' => 'Й',
+ 'й' => 'й',
+ 'ѐ' => 'ѐ',
+ 'ё' => 'ё',
+ 'ѓ' => 'ѓ',
+ 'ї' => 'ї',
+ 'ќ' => 'ќ',
+ 'ѝ' => 'ѝ',
+ 'ў' => 'ў',
+ 'Ѷ' => 'Ѷ',
+ 'ѷ' => 'ѷ',
+ 'Ӂ' => 'Ӂ',
+ 'ӂ' => 'ӂ',
+ 'Ӑ' => 'Ӑ',
+ 'ӑ' => 'ӑ',
+ 'Ӓ' => 'Ӓ',
+ 'ӓ' => 'ӓ',
+ 'Ӗ' => 'Ӗ',
+ 'ӗ' => 'ӗ',
+ 'Ӛ' => 'Ӛ',
+ 'ӛ' => 'ӛ',
+ 'Ӝ' => 'Ӝ',
+ 'ӝ' => 'ӝ',
+ 'Ӟ' => 'Ӟ',
+ 'ӟ' => 'ӟ',
+ 'Ӣ' => 'Ӣ',
+ 'ӣ' => 'ӣ',
+ 'Ӥ' => 'Ӥ',
+ 'ӥ' => 'ӥ',
+ 'Ӧ' => 'Ӧ',
+ 'ӧ' => 'ӧ',
+ 'Ӫ' => 'Ӫ',
+ 'ӫ' => 'ӫ',
+ 'Ӭ' => 'Ӭ',
+ 'ӭ' => 'ӭ',
+ 'Ӯ' => 'Ӯ',
+ 'ӯ' => 'ӯ',
+ 'Ӱ' => 'Ӱ',
+ 'ӱ' => 'ӱ',
+ 'Ӳ' => 'Ӳ',
+ 'ӳ' => 'ӳ',
+ 'Ӵ' => 'Ӵ',
+ 'ӵ' => 'ӵ',
+ 'Ӹ' => 'Ӹ',
+ 'ӹ' => 'ӹ',
+ 'آ' => 'آ',
+ 'أ' => 'أ',
+ 'ؤ' => 'ؤ',
+ 'إ' => 'إ',
+ 'ئ' => 'ئ',
+ 'ۀ' => 'ۀ',
+ 'ۂ' => 'ۂ',
+ 'ۓ' => 'ۓ',
+ 'ऩ' => 'ऩ',
+ 'ऱ' => 'ऱ',
+ 'ऴ' => 'ऴ',
+ 'क़' => 'क़',
+ 'ख़' => 'ख़',
+ 'ग़' => 'ग़',
+ 'ज़' => 'ज़',
+ 'ड़' => 'ड़',
+ 'ढ़' => 'ढ़',
+ 'फ़' => 'फ़',
+ 'य़' => 'य़',
+ 'ো' => 'ো',
+ 'ৌ' => 'ৌ',
+ 'ড়' => 'ড়',
+ 'ঢ়' => 'ঢ়',
+ 'য়' => 'য়',
+ 'ਲ਼' => 'ਲ਼',
+ 'ਸ਼' => 'ਸ਼',
+ 'ਖ਼' => 'ਖ਼',
+ 'ਗ਼' => 'ਗ਼',
+ 'ਜ਼' => 'ਜ਼',
+ 'ਫ਼' => 'ਫ਼',
+ 'ୈ' => 'ୈ',
+ 'ୋ' => 'ୋ',
+ 'ୌ' => 'ୌ',
+ 'ଡ଼' => 'ଡ଼',
+ 'ଢ଼' => 'ଢ଼',
+ 'ஔ' => 'ஔ',
+ 'ொ' => 'ொ',
+ 'ோ' => 'ோ',
+ 'ௌ' => 'ௌ',
+ 'ై' => 'ై',
+ 'ೀ' => 'ೀ',
+ 'ೇ' => 'ೇ',
+ 'ೈ' => 'ೈ',
+ 'ೊ' => 'ೊ',
+ 'ೋ' => 'ೋ',
+ 'ൊ' => 'ൊ',
+ 'ോ' => 'ോ',
+ 'ൌ' => 'ൌ',
+ 'ේ' => 'ේ',
+ 'ො' => 'ො',
+ 'ෝ' => 'ෝ',
+ 'ෞ' => 'ෞ',
+ 'གྷ' => 'གྷ',
+ 'ཌྷ' => 'ཌྷ',
+ 'དྷ' => 'དྷ',
+ 'བྷ' => 'བྷ',
+ 'ཛྷ' => 'ཛྷ',
+ 'ཀྵ' => 'ཀྵ',
+ 'ཱི' => 'ཱི',
+ 'ཱུ' => 'ཱུ',
+ 'ྲྀ' => 'ྲྀ',
+ 'ླྀ' => 'ླྀ',
+ 'ཱྀ' => 'ཱྀ',
+ 'ྒྷ' => 'ྒྷ',
+ 'ྜྷ' => 'ྜྷ',
+ 'ྡྷ' => 'ྡྷ',
+ 'ྦྷ' => 'ྦྷ',
+ 'ྫྷ' => 'ྫྷ',
+ 'ྐྵ' => 'ྐྵ',
+ 'ဦ' => 'ဦ',
+ 'ᬆ' => 'ᬆ',
+ 'ᬈ' => 'ᬈ',
+ 'ᬊ' => 'ᬊ',
+ 'ᬌ' => 'ᬌ',
+ 'ᬎ' => 'ᬎ',
+ 'ᬒ' => 'ᬒ',
+ 'ᬻ' => 'ᬻ',
+ 'ᬽ' => 'ᬽ',
+ 'ᭀ' => 'ᭀ',
+ 'ᭁ' => 'ᭁ',
+ 'ᭃ' => 'ᭃ',
+ 'Ḁ' => 'Ḁ',
+ 'ḁ' => 'ḁ',
+ 'Ḃ' => 'Ḃ',
+ 'ḃ' => 'ḃ',
+ 'Ḅ' => 'Ḅ',
+ 'ḅ' => 'ḅ',
+ 'Ḇ' => 'Ḇ',
+ 'ḇ' => 'ḇ',
+ 'Ḉ' => 'Ḉ',
+ 'ḉ' => 'ḉ',
+ 'Ḋ' => 'Ḋ',
+ 'ḋ' => 'ḋ',
+ 'Ḍ' => 'Ḍ',
+ 'ḍ' => 'ḍ',
+ 'Ḏ' => 'Ḏ',
+ 'ḏ' => 'ḏ',
+ 'Ḑ' => 'Ḑ',
+ 'ḑ' => 'ḑ',
+ 'Ḓ' => 'Ḓ',
+ 'ḓ' => 'ḓ',
+ 'Ḕ' => 'Ḕ',
+ 'ḕ' => 'ḕ',
+ 'Ḗ' => 'Ḗ',
+ 'ḗ' => 'ḗ',
+ 'Ḙ' => 'Ḙ',
+ 'ḙ' => 'ḙ',
+ 'Ḛ' => 'Ḛ',
+ 'ḛ' => 'ḛ',
+ 'Ḝ' => 'Ḝ',
+ 'ḝ' => 'ḝ',
+ 'Ḟ' => 'Ḟ',
+ 'ḟ' => 'ḟ',
+ 'Ḡ' => 'Ḡ',
+ 'ḡ' => 'ḡ',
+ 'Ḣ' => 'Ḣ',
+ 'ḣ' => 'ḣ',
+ 'Ḥ' => 'Ḥ',
+ 'ḥ' => 'ḥ',
+ 'Ḧ' => 'Ḧ',
+ 'ḧ' => 'ḧ',
+ 'Ḩ' => 'Ḩ',
+ 'ḩ' => 'ḩ',
+ 'Ḫ' => 'Ḫ',
+ 'ḫ' => 'ḫ',
+ 'Ḭ' => 'Ḭ',
+ 'ḭ' => 'ḭ',
+ 'Ḯ' => 'Ḯ',
+ 'ḯ' => 'ḯ',
+ 'Ḱ' => 'Ḱ',
+ 'ḱ' => 'ḱ',
+ 'Ḳ' => 'Ḳ',
+ 'ḳ' => 'ḳ',
+ 'Ḵ' => 'Ḵ',
+ 'ḵ' => 'ḵ',
+ 'Ḷ' => 'Ḷ',
+ 'ḷ' => 'ḷ',
+ 'Ḹ' => 'Ḹ',
+ 'ḹ' => 'ḹ',
+ 'Ḻ' => 'Ḻ',
+ 'ḻ' => 'ḻ',
+ 'Ḽ' => 'Ḽ',
+ 'ḽ' => 'ḽ',
+ 'Ḿ' => 'Ḿ',
+ 'ḿ' => 'ḿ',
+ 'Ṁ' => 'Ṁ',
+ 'ṁ' => 'ṁ',
+ 'Ṃ' => 'Ṃ',
+ 'ṃ' => 'ṃ',
+ 'Ṅ' => 'Ṅ',
+ 'ṅ' => 'ṅ',
+ 'Ṇ' => 'Ṇ',
+ 'ṇ' => 'ṇ',
+ 'Ṉ' => 'Ṉ',
+ 'ṉ' => 'ṉ',
+ 'Ṋ' => 'Ṋ',
+ 'ṋ' => 'ṋ',
+ 'Ṍ' => 'Ṍ',
+ 'ṍ' => 'ṍ',
+ 'Ṏ' => 'Ṏ',
+ 'ṏ' => 'ṏ',
+ 'Ṑ' => 'Ṑ',
+ 'ṑ' => 'ṑ',
+ 'Ṓ' => 'Ṓ',
+ 'ṓ' => 'ṓ',
+ 'Ṕ' => 'Ṕ',
+ 'ṕ' => 'ṕ',
+ 'Ṗ' => 'Ṗ',
+ 'ṗ' => 'ṗ',
+ 'Ṙ' => 'Ṙ',
+ 'ṙ' => 'ṙ',
+ 'Ṛ' => 'Ṛ',
+ 'ṛ' => 'ṛ',
+ 'Ṝ' => 'Ṝ',
+ 'ṝ' => 'ṝ',
+ 'Ṟ' => 'Ṟ',
+ 'ṟ' => 'ṟ',
+ 'Ṡ' => 'Ṡ',
+ 'ṡ' => 'ṡ',
+ 'Ṣ' => 'Ṣ',
+ 'ṣ' => 'ṣ',
+ 'Ṥ' => 'Ṥ',
+ 'ṥ' => 'ṥ',
+ 'Ṧ' => 'Ṧ',
+ 'ṧ' => 'ṧ',
+ 'Ṩ' => 'Ṩ',
+ 'ṩ' => 'ṩ',
+ 'Ṫ' => 'Ṫ',
+ 'ṫ' => 'ṫ',
+ 'Ṭ' => 'Ṭ',
+ 'ṭ' => 'ṭ',
+ 'Ṯ' => 'Ṯ',
+ 'ṯ' => 'ṯ',
+ 'Ṱ' => 'Ṱ',
+ 'ṱ' => 'ṱ',
+ 'Ṳ' => 'Ṳ',
+ 'ṳ' => 'ṳ',
+ 'Ṵ' => 'Ṵ',
+ 'ṵ' => 'ṵ',
+ 'Ṷ' => 'Ṷ',
+ 'ṷ' => 'ṷ',
+ 'Ṹ' => 'Ṹ',
+ 'ṹ' => 'ṹ',
+ 'Ṻ' => 'Ṻ',
+ 'ṻ' => 'ṻ',
+ 'Ṽ' => 'Ṽ',
+ 'ṽ' => 'ṽ',
+ 'Ṿ' => 'Ṿ',
+ 'ṿ' => 'ṿ',
+ 'Ẁ' => 'Ẁ',
+ 'ẁ' => 'ẁ',
+ 'Ẃ' => 'Ẃ',
+ 'ẃ' => 'ẃ',
+ 'Ẅ' => 'Ẅ',
+ 'ẅ' => 'ẅ',
+ 'Ẇ' => 'Ẇ',
+ 'ẇ' => 'ẇ',
+ 'Ẉ' => 'Ẉ',
+ 'ẉ' => 'ẉ',
+ 'Ẋ' => 'Ẋ',
+ 'ẋ' => 'ẋ',
+ 'Ẍ' => 'Ẍ',
+ 'ẍ' => 'ẍ',
+ 'Ẏ' => 'Ẏ',
+ 'ẏ' => 'ẏ',
+ 'Ẑ' => 'Ẑ',
+ 'ẑ' => 'ẑ',
+ 'Ẓ' => 'Ẓ',
+ 'ẓ' => 'ẓ',
+ 'Ẕ' => 'Ẕ',
+ 'ẕ' => 'ẕ',
+ 'ẖ' => 'ẖ',
+ 'ẗ' => 'ẗ',
+ 'ẘ' => 'ẘ',
+ 'ẙ' => 'ẙ',
+ 'ẛ' => 'ẛ',
+ 'Ạ' => 'Ạ',
+ 'ạ' => 'ạ',
+ 'Ả' => 'Ả',
+ 'ả' => 'ả',
+ 'Ấ' => 'Ấ',
+ 'ấ' => 'ấ',
+ 'Ầ' => 'Ầ',
+ 'ầ' => 'ầ',
+ 'Ẩ' => 'Ẩ',
+ 'ẩ' => 'ẩ',
+ 'Ẫ' => 'Ẫ',
+ 'ẫ' => 'ẫ',
+ 'Ậ' => 'Ậ',
+ 'ậ' => 'ậ',
+ 'Ắ' => 'Ắ',
+ 'ắ' => 'ắ',
+ 'Ằ' => 'Ằ',
+ 'ằ' => 'ằ',
+ 'Ẳ' => 'Ẳ',
+ 'ẳ' => 'ẳ',
+ 'Ẵ' => 'Ẵ',
+ 'ẵ' => 'ẵ',
+ 'Ặ' => 'Ặ',
+ 'ặ' => 'ặ',
+ 'Ẹ' => 'Ẹ',
+ 'ẹ' => 'ẹ',
+ 'Ẻ' => 'Ẻ',
+ 'ẻ' => 'ẻ',
+ 'Ẽ' => 'Ẽ',
+ 'ẽ' => 'ẽ',
+ 'Ế' => 'Ế',
+ 'ế' => 'ế',
+ 'Ề' => 'Ề',
+ 'ề' => 'ề',
+ 'Ể' => 'Ể',
+ 'ể' => 'ể',
+ 'Ễ' => 'Ễ',
+ 'ễ' => 'ễ',
+ 'Ệ' => 'Ệ',
+ 'ệ' => 'ệ',
+ 'Ỉ' => 'Ỉ',
+ 'ỉ' => 'ỉ',
+ 'Ị' => 'Ị',
+ 'ị' => 'ị',
+ 'Ọ' => 'Ọ',
+ 'ọ' => 'ọ',
+ 'Ỏ' => 'Ỏ',
+ 'ỏ' => 'ỏ',
+ 'Ố' => 'Ố',
+ 'ố' => 'ố',
+ 'Ồ' => 'Ồ',
+ 'ồ' => 'ồ',
+ 'Ổ' => 'Ổ',
+ 'ổ' => 'ổ',
+ 'Ỗ' => 'Ỗ',
+ 'ỗ' => 'ỗ',
+ 'Ộ' => 'Ộ',
+ 'ộ' => 'ộ',
+ 'Ớ' => 'Ớ',
+ 'ớ' => 'ớ',
+ 'Ờ' => 'Ờ',
+ 'ờ' => 'ờ',
+ 'Ở' => 'Ở',
+ 'ở' => 'ở',
+ 'Ỡ' => 'Ỡ',
+ 'ỡ' => 'ỡ',
+ 'Ợ' => 'Ợ',
+ 'ợ' => 'ợ',
+ 'Ụ' => 'Ụ',
+ 'ụ' => 'ụ',
+ 'Ủ' => 'Ủ',
+ 'ủ' => 'ủ',
+ 'Ứ' => 'Ứ',
+ 'ứ' => 'ứ',
+ 'Ừ' => 'Ừ',
+ 'ừ' => 'ừ',
+ 'Ử' => 'Ử',
+ 'ử' => 'ử',
+ 'Ữ' => 'Ữ',
+ 'ữ' => 'ữ',
+ 'Ự' => 'Ự',
+ 'ự' => 'ự',
+ 'Ỳ' => 'Ỳ',
+ 'ỳ' => 'ỳ',
+ 'Ỵ' => 'Ỵ',
+ 'ỵ' => 'ỵ',
+ 'Ỷ' => 'Ỷ',
+ 'ỷ' => 'ỷ',
+ 'Ỹ' => 'Ỹ',
+ 'ỹ' => 'ỹ',
+ 'ἀ' => 'ἀ',
+ 'ἁ' => 'ἁ',
+ 'ἂ' => 'ἂ',
+ 'ἃ' => 'ἃ',
+ 'ἄ' => 'ἄ',
+ 'ἅ' => 'ἅ',
+ 'ἆ' => 'ἆ',
+ 'ἇ' => 'ἇ',
+ 'Ἀ' => 'Ἀ',
+ 'Ἁ' => 'Ἁ',
+ 'Ἂ' => 'Ἂ',
+ 'Ἃ' => 'Ἃ',
+ 'Ἄ' => 'Ἄ',
+ 'Ἅ' => 'Ἅ',
+ 'Ἆ' => 'Ἆ',
+ 'Ἇ' => 'Ἇ',
+ 'ἐ' => 'ἐ',
+ 'ἑ' => 'ἑ',
+ 'ἒ' => 'ἒ',
+ 'ἓ' => 'ἓ',
+ 'ἔ' => 'ἔ',
+ 'ἕ' => 'ἕ',
+ 'Ἐ' => 'Ἐ',
+ 'Ἑ' => 'Ἑ',
+ 'Ἒ' => 'Ἒ',
+ 'Ἓ' => 'Ἓ',
+ 'Ἔ' => 'Ἔ',
+ 'Ἕ' => 'Ἕ',
+ 'ἠ' => 'ἠ',
+ 'ἡ' => 'ἡ',
+ 'ἢ' => 'ἢ',
+ 'ἣ' => 'ἣ',
+ 'ἤ' => 'ἤ',
+ 'ἥ' => 'ἥ',
+ 'ἦ' => 'ἦ',
+ 'ἧ' => 'ἧ',
+ 'Ἠ' => 'Ἠ',
+ 'Ἡ' => 'Ἡ',
+ 'Ἢ' => 'Ἢ',
+ 'Ἣ' => 'Ἣ',
+ 'Ἤ' => 'Ἤ',
+ 'Ἥ' => 'Ἥ',
+ 'Ἦ' => 'Ἦ',
+ 'Ἧ' => 'Ἧ',
+ 'ἰ' => 'ἰ',
+ 'ἱ' => 'ἱ',
+ 'ἲ' => 'ἲ',
+ 'ἳ' => 'ἳ',
+ 'ἴ' => 'ἴ',
+ 'ἵ' => 'ἵ',
+ 'ἶ' => 'ἶ',
+ 'ἷ' => 'ἷ',
+ 'Ἰ' => 'Ἰ',
+ 'Ἱ' => 'Ἱ',
+ 'Ἲ' => 'Ἲ',
+ 'Ἳ' => 'Ἳ',
+ 'Ἴ' => 'Ἴ',
+ 'Ἵ' => 'Ἵ',
+ 'Ἶ' => 'Ἶ',
+ 'Ἷ' => 'Ἷ',
+ 'ὀ' => 'ὀ',
+ 'ὁ' => 'ὁ',
+ 'ὂ' => 'ὂ',
+ 'ὃ' => 'ὃ',
+ 'ὄ' => 'ὄ',
+ 'ὅ' => 'ὅ',
+ 'Ὀ' => 'Ὀ',
+ 'Ὁ' => 'Ὁ',
+ 'Ὂ' => 'Ὂ',
+ 'Ὃ' => 'Ὃ',
+ 'Ὄ' => 'Ὄ',
+ 'Ὅ' => 'Ὅ',
+ 'ὐ' => 'ὐ',
+ 'ὑ' => 'ὑ',
+ 'ὒ' => 'ὒ',
+ 'ὓ' => 'ὓ',
+ 'ὔ' => 'ὔ',
+ 'ὕ' => 'ὕ',
+ 'ὖ' => 'ὖ',
+ 'ὗ' => 'ὗ',
+ 'Ὑ' => 'Ὑ',
+ 'Ὓ' => 'Ὓ',
+ 'Ὕ' => 'Ὕ',
+ 'Ὗ' => 'Ὗ',
+ 'ὠ' => 'ὠ',
+ 'ὡ' => 'ὡ',
+ 'ὢ' => 'ὢ',
+ 'ὣ' => 'ὣ',
+ 'ὤ' => 'ὤ',
+ 'ὥ' => 'ὥ',
+ 'ὦ' => 'ὦ',
+ 'ὧ' => 'ὧ',
+ 'Ὠ' => 'Ὠ',
+ 'Ὡ' => 'Ὡ',
+ 'Ὢ' => 'Ὢ',
+ 'Ὣ' => 'Ὣ',
+ 'Ὤ' => 'Ὤ',
+ 'Ὥ' => 'Ὥ',
+ 'Ὦ' => 'Ὦ',
+ 'Ὧ' => 'Ὧ',
+ 'ὰ' => 'ὰ',
+ 'ά' => 'ά',
+ 'ὲ' => 'ὲ',
+ 'έ' => 'έ',
+ 'ὴ' => 'ὴ',
+ 'ή' => 'ή',
+ 'ὶ' => 'ὶ',
+ 'ί' => 'ί',
+ 'ὸ' => 'ὸ',
+ 'ό' => 'ό',
+ 'ὺ' => 'ὺ',
+ 'ύ' => 'ύ',
+ 'ὼ' => 'ὼ',
+ 'ώ' => 'ώ',
+ 'ᾀ' => 'ᾀ',
+ 'ᾁ' => 'ᾁ',
+ 'ᾂ' => 'ᾂ',
+ 'ᾃ' => 'ᾃ',
+ 'ᾄ' => 'ᾄ',
+ 'ᾅ' => 'ᾅ',
+ 'ᾆ' => 'ᾆ',
+ 'ᾇ' => 'ᾇ',
+ 'ᾈ' => 'ᾈ',
+ 'ᾉ' => 'ᾉ',
+ 'ᾊ' => 'ᾊ',
+ 'ᾋ' => 'ᾋ',
+ 'ᾌ' => 'ᾌ',
+ 'ᾍ' => 'ᾍ',
+ 'ᾎ' => 'ᾎ',
+ 'ᾏ' => 'ᾏ',
+ 'ᾐ' => 'ᾐ',
+ 'ᾑ' => 'ᾑ',
+ 'ᾒ' => 'ᾒ',
+ 'ᾓ' => 'ᾓ',
+ 'ᾔ' => 'ᾔ',
+ 'ᾕ' => 'ᾕ',
+ 'ᾖ' => 'ᾖ',
+ 'ᾗ' => 'ᾗ',
+ 'ᾘ' => 'ᾘ',
+ 'ᾙ' => 'ᾙ',
+ 'ᾚ' => 'ᾚ',
+ 'ᾛ' => 'ᾛ',
+ 'ᾜ' => 'ᾜ',
+ 'ᾝ' => 'ᾝ',
+ 'ᾞ' => 'ᾞ',
+ 'ᾟ' => 'ᾟ',
+ 'ᾠ' => 'ᾠ',
+ 'ᾡ' => 'ᾡ',
+ 'ᾢ' => 'ᾢ',
+ 'ᾣ' => 'ᾣ',
+ 'ᾤ' => 'ᾤ',
+ 'ᾥ' => 'ᾥ',
+ 'ᾦ' => 'ᾦ',
+ 'ᾧ' => 'ᾧ',
+ 'ᾨ' => 'ᾨ',
+ 'ᾩ' => 'ᾩ',
+ 'ᾪ' => 'ᾪ',
+ 'ᾫ' => 'ᾫ',
+ 'ᾬ' => 'ᾬ',
+ 'ᾭ' => 'ᾭ',
+ 'ᾮ' => 'ᾮ',
+ 'ᾯ' => 'ᾯ',
+ 'ᾰ' => 'ᾰ',
+ 'ᾱ' => 'ᾱ',
+ 'ᾲ' => 'ᾲ',
+ 'ᾳ' => 'ᾳ',
+ 'ᾴ' => 'ᾴ',
+ 'ᾶ' => 'ᾶ',
+ 'ᾷ' => 'ᾷ',
+ 'Ᾰ' => 'Ᾰ',
+ 'Ᾱ' => 'Ᾱ',
+ 'Ὰ' => 'Ὰ',
+ 'Ά' => 'Ά',
+ 'ᾼ' => 'ᾼ',
+ 'ι' => 'ι',
+ '῁' => '῁',
+ 'ῂ' => 'ῂ',
+ 'ῃ' => 'ῃ',
+ 'ῄ' => 'ῄ',
+ 'ῆ' => 'ῆ',
+ 'ῇ' => 'ῇ',
+ 'Ὲ' => 'Ὲ',
+ 'Έ' => 'Έ',
+ 'Ὴ' => 'Ὴ',
+ 'Ή' => 'Ή',
+ 'ῌ' => 'ῌ',
+ '῍' => '῍',
+ '῎' => '῎',
+ '῏' => '῏',
+ 'ῐ' => 'ῐ',
+ 'ῑ' => 'ῑ',
+ 'ῒ' => 'ῒ',
+ 'ΐ' => 'ΐ',
+ 'ῖ' => 'ῖ',
+ 'ῗ' => 'ῗ',
+ 'Ῐ' => 'Ῐ',
+ 'Ῑ' => 'Ῑ',
+ 'Ὶ' => 'Ὶ',
+ 'Ί' => 'Ί',
+ '῝' => '῝',
+ '῞' => '῞',
+ '῟' => '῟',
+ 'ῠ' => 'ῠ',
+ 'ῡ' => 'ῡ',
+ 'ῢ' => 'ῢ',
+ 'ΰ' => 'ΰ',
+ 'ῤ' => 'ῤ',
+ 'ῥ' => 'ῥ',
+ 'ῦ' => 'ῦ',
+ 'ῧ' => 'ῧ',
+ 'Ῠ' => 'Ῠ',
+ 'Ῡ' => 'Ῡ',
+ 'Ὺ' => 'Ὺ',
+ 'Ύ' => 'Ύ',
+ 'Ῥ' => 'Ῥ',
+ '῭' => '῭',
+ '΅' => '΅',
+ '`' => '`',
+ 'ῲ' => 'ῲ',
+ 'ῳ' => 'ῳ',
+ 'ῴ' => 'ῴ',
+ 'ῶ' => 'ῶ',
+ 'ῷ' => 'ῷ',
+ 'Ὸ' => 'Ὸ',
+ 'Ό' => 'Ό',
+ 'Ὼ' => 'Ὼ',
+ 'Ώ' => 'Ώ',
+ 'ῼ' => 'ῼ',
+ '´' => '´',
+ ' ' => ' ',
+ ' ' => ' ',
+ 'Ω' => 'Ω',
+ 'K' => 'K',
+ 'Å' => 'Å',
+ '↚' => '↚',
+ '↛' => '↛',
+ '↮' => '↮',
+ '⇍' => '⇍',
+ '⇎' => '⇎',
+ '⇏' => '⇏',
+ '∄' => '∄',
+ '∉' => '∉',
+ '∌' => '∌',
+ '∤' => '∤',
+ '∦' => '∦',
+ '≁' => '≁',
+ '≄' => '≄',
+ '≇' => '≇',
+ '≉' => '≉',
+ '≠' => '≠',
+ '≢' => '≢',
+ '≭' => '≭',
+ '≮' => '≮',
+ '≯' => '≯',
+ '≰' => '≰',
+ '≱' => '≱',
+ '≴' => '≴',
+ '≵' => '≵',
+ '≸' => '≸',
+ '≹' => '≹',
+ '⊀' => '⊀',
+ '⊁' => '⊁',
+ '⊄' => '⊄',
+ '⊅' => '⊅',
+ '⊈' => '⊈',
+ '⊉' => '⊉',
+ '⊬' => '⊬',
+ '⊭' => '⊭',
+ '⊮' => '⊮',
+ '⊯' => '⊯',
+ '⋠' => '⋠',
+ '⋡' => '⋡',
+ '⋢' => '⋢',
+ '⋣' => '⋣',
+ '⋪' => '⋪',
+ '⋫' => '⋫',
+ '⋬' => '⋬',
+ '⋭' => '⋭',
+ '〈' => '〈',
+ '〉' => '〉',
+ '⫝̸' => '⫝̸',
+ 'が' => 'が',
+ 'ぎ' => 'ぎ',
+ 'ぐ' => 'ぐ',
+ 'げ' => 'げ',
+ 'ご' => 'ご',
+ 'ざ' => 'ざ',
+ 'じ' => 'じ',
+ 'ず' => 'ず',
+ 'ぜ' => 'ぜ',
+ 'ぞ' => 'ぞ',
+ 'だ' => 'だ',
+ 'ぢ' => 'ぢ',
+ 'づ' => 'づ',
+ 'で' => 'で',
+ 'ど' => 'ど',
+ 'ば' => 'ば',
+ 'ぱ' => 'ぱ',
+ 'び' => 'び',
+ 'ぴ' => 'ぴ',
+ 'ぶ' => 'ぶ',
+ 'ぷ' => 'ぷ',
+ 'べ' => 'べ',
+ 'ぺ' => 'ぺ',
+ 'ぼ' => 'ぼ',
+ 'ぽ' => 'ぽ',
+ 'ゔ' => 'ゔ',
+ 'ゞ' => 'ゞ',
+ 'ガ' => 'ガ',
+ 'ギ' => 'ギ',
+ 'グ' => 'グ',
+ 'ゲ' => 'ゲ',
+ 'ゴ' => 'ゴ',
+ 'ザ' => 'ザ',
+ 'ジ' => 'ジ',
+ 'ズ' => 'ズ',
+ 'ゼ' => 'ゼ',
+ 'ゾ' => 'ゾ',
+ 'ダ' => 'ダ',
+ 'ヂ' => 'ヂ',
+ 'ヅ' => 'ヅ',
+ 'デ' => 'デ',
+ 'ド' => 'ド',
+ 'バ' => 'バ',
+ 'パ' => 'パ',
+ 'ビ' => 'ビ',
+ 'ピ' => 'ピ',
+ 'ブ' => 'ブ',
+ 'プ' => 'プ',
+ 'ベ' => 'ベ',
+ 'ペ' => 'ペ',
+ 'ボ' => 'ボ',
+ 'ポ' => 'ポ',
+ 'ヴ' => 'ヴ',
+ 'ヷ' => 'ヷ',
+ 'ヸ' => 'ヸ',
+ 'ヹ' => 'ヹ',
+ 'ヺ' => 'ヺ',
+ 'ヾ' => 'ヾ',
+ '豈' => '豈',
+ '更' => '更',
+ '車' => '車',
+ '賈' => '賈',
+ '滑' => '滑',
+ '串' => '串',
+ '句' => '句',
+ '龜' => '龜',
+ '龜' => '龜',
+ '契' => '契',
+ '金' => '金',
+ '喇' => '喇',
+ '奈' => '奈',
+ '懶' => '懶',
+ '癩' => '癩',
+ '羅' => '羅',
+ '蘿' => '蘿',
+ '螺' => '螺',
+ '裸' => '裸',
+ '邏' => '邏',
+ '樂' => '樂',
+ '洛' => '洛',
+ '烙' => '烙',
+ '珞' => '珞',
+ '落' => '落',
+ '酪' => '酪',
+ '駱' => '駱',
+ '亂' => '亂',
+ '卵' => '卵',
+ '欄' => '欄',
+ '爛' => '爛',
+ '蘭' => '蘭',
+ '鸞' => '鸞',
+ '嵐' => '嵐',
+ '濫' => '濫',
+ '藍' => '藍',
+ '襤' => '襤',
+ '拉' => '拉',
+ '臘' => '臘',
+ '蠟' => '蠟',
+ '廊' => '廊',
+ '朗' => '朗',
+ '浪' => '浪',
+ '狼' => '狼',
+ '郎' => '郎',
+ '來' => '來',
+ '冷' => '冷',
+ '勞' => '勞',
+ '擄' => '擄',
+ '櫓' => '櫓',
+ '爐' => '爐',
+ '盧' => '盧',
+ '老' => '老',
+ '蘆' => '蘆',
+ '虜' => '虜',
+ '路' => '路',
+ '露' => '露',
+ '魯' => '魯',
+ '鷺' => '鷺',
+ '碌' => '碌',
+ '祿' => '祿',
+ '綠' => '綠',
+ '菉' => '菉',
+ '錄' => '錄',
+ '鹿' => '鹿',
+ '論' => '論',
+ '壟' => '壟',
+ '弄' => '弄',
+ '籠' => '籠',
+ '聾' => '聾',
+ '牢' => '牢',
+ '磊' => '磊',
+ '賂' => '賂',
+ '雷' => '雷',
+ '壘' => '壘',
+ '屢' => '屢',
+ '樓' => '樓',
+ '淚' => '淚',
+ '漏' => '漏',
+ '累' => '累',
+ '縷' => '縷',
+ '陋' => '陋',
+ '勒' => '勒',
+ '肋' => '肋',
+ '凜' => '凜',
+ '凌' => '凌',
+ '稜' => '稜',
+ '綾' => '綾',
+ '菱' => '菱',
+ '陵' => '陵',
+ '讀' => '讀',
+ '拏' => '拏',
+ '樂' => '樂',
+ '諾' => '諾',
+ '丹' => '丹',
+ '寧' => '寧',
+ '怒' => '怒',
+ '率' => '率',
+ '異' => '異',
+ '北' => '北',
+ '磻' => '磻',
+ '便' => '便',
+ '復' => '復',
+ '不' => '不',
+ '泌' => '泌',
+ '數' => '數',
+ '索' => '索',
+ '參' => '參',
+ '塞' => '塞',
+ '省' => '省',
+ '葉' => '葉',
+ '說' => '說',
+ '殺' => '殺',
+ '辰' => '辰',
+ '沈' => '沈',
+ '拾' => '拾',
+ '若' => '若',
+ '掠' => '掠',
+ '略' => '略',
+ '亮' => '亮',
+ '兩' => '兩',
+ '凉' => '凉',
+ '梁' => '梁',
+ '糧' => '糧',
+ '良' => '良',
+ '諒' => '諒',
+ '量' => '量',
+ '勵' => '勵',
+ '呂' => '呂',
+ '女' => '女',
+ '廬' => '廬',
+ '旅' => '旅',
+ '濾' => '濾',
+ '礪' => '礪',
+ '閭' => '閭',
+ '驪' => '驪',
+ '麗' => '麗',
+ '黎' => '黎',
+ '力' => '力',
+ '曆' => '曆',
+ '歷' => '歷',
+ '轢' => '轢',
+ '年' => '年',
+ '憐' => '憐',
+ '戀' => '戀',
+ '撚' => '撚',
+ '漣' => '漣',
+ '煉' => '煉',
+ '璉' => '璉',
+ '秊' => '秊',
+ '練' => '練',
+ '聯' => '聯',
+ '輦' => '輦',
+ '蓮' => '蓮',
+ '連' => '連',
+ '鍊' => '鍊',
+ '列' => '列',
+ '劣' => '劣',
+ '咽' => '咽',
+ '烈' => '烈',
+ '裂' => '裂',
+ '說' => '說',
+ '廉' => '廉',
+ '念' => '念',
+ '捻' => '捻',
+ '殮' => '殮',
+ '簾' => '簾',
+ '獵' => '獵',
+ '令' => '令',
+ '囹' => '囹',
+ '寧' => '寧',
+ '嶺' => '嶺',
+ '怜' => '怜',
+ '玲' => '玲',
+ '瑩' => '瑩',
+ '羚' => '羚',
+ '聆' => '聆',
+ '鈴' => '鈴',
+ '零' => '零',
+ '靈' => '靈',
+ '領' => '領',
+ '例' => '例',
+ '禮' => '禮',
+ '醴' => '醴',
+ '隸' => '隸',
+ '惡' => '惡',
+ '了' => '了',
+ '僚' => '僚',
+ '寮' => '寮',
+ '尿' => '尿',
+ '料' => '料',
+ '樂' => '樂',
+ '燎' => '燎',
+ '療' => '療',
+ '蓼' => '蓼',
+ '遼' => '遼',
+ '龍' => '龍',
+ '暈' => '暈',
+ '阮' => '阮',
+ '劉' => '劉',
+ '杻' => '杻',
+ '柳' => '柳',
+ '流' => '流',
+ '溜' => '溜',
+ '琉' => '琉',
+ '留' => '留',
+ '硫' => '硫',
+ '紐' => '紐',
+ '類' => '類',
+ '六' => '六',
+ '戮' => '戮',
+ '陸' => '陸',
+ '倫' => '倫',
+ '崙' => '崙',
+ '淪' => '淪',
+ '輪' => '輪',
+ '律' => '律',
+ '慄' => '慄',
+ '栗' => '栗',
+ '率' => '率',
+ '隆' => '隆',
+ '利' => '利',
+ '吏' => '吏',
+ '履' => '履',
+ '易' => '易',
+ '李' => '李',
+ '梨' => '梨',
+ '泥' => '泥',
+ '理' => '理',
+ '痢' => '痢',
+ '罹' => '罹',
+ '裏' => '裏',
+ '裡' => '裡',
+ '里' => '里',
+ '離' => '離',
+ '匿' => '匿',
+ '溺' => '溺',
+ '吝' => '吝',
+ '燐' => '燐',
+ '璘' => '璘',
+ '藺' => '藺',
+ '隣' => '隣',
+ '鱗' => '鱗',
+ '麟' => '麟',
+ '林' => '林',
+ '淋' => '淋',
+ '臨' => '臨',
+ '立' => '立',
+ '笠' => '笠',
+ '粒' => '粒',
+ '狀' => '狀',
+ '炙' => '炙',
+ '識' => '識',
+ '什' => '什',
+ '茶' => '茶',
+ '刺' => '刺',
+ '切' => '切',
+ '度' => '度',
+ '拓' => '拓',
+ '糖' => '糖',
+ '宅' => '宅',
+ '洞' => '洞',
+ '暴' => '暴',
+ '輻' => '輻',
+ '行' => '行',
+ '降' => '降',
+ '見' => '見',
+ '廓' => '廓',
+ '兀' => '兀',
+ '嗀' => '嗀',
+ '塚' => '塚',
+ '晴' => '晴',
+ '凞' => '凞',
+ '猪' => '猪',
+ '益' => '益',
+ '礼' => '礼',
+ '神' => '神',
+ '祥' => '祥',
+ '福' => '福',
+ '靖' => '靖',
+ '精' => '精',
+ '羽' => '羽',
+ '蘒' => '蘒',
+ '諸' => '諸',
+ '逸' => '逸',
+ '都' => '都',
+ '飯' => '飯',
+ '飼' => '飼',
+ '館' => '館',
+ '鶴' => '鶴',
+ '郞' => '郞',
+ '隷' => '隷',
+ '侮' => '侮',
+ '僧' => '僧',
+ '免' => '免',
+ '勉' => '勉',
+ '勤' => '勤',
+ '卑' => '卑',
+ '喝' => '喝',
+ '嘆' => '嘆',
+ '器' => '器',
+ '塀' => '塀',
+ '墨' => '墨',
+ '層' => '層',
+ '屮' => '屮',
+ '悔' => '悔',
+ '慨' => '慨',
+ '憎' => '憎',
+ '懲' => '懲',
+ '敏' => '敏',
+ '既' => '既',
+ '暑' => '暑',
+ '梅' => '梅',
+ '海' => '海',
+ '渚' => '渚',
+ '漢' => '漢',
+ '煮' => '煮',
+ '爫' => '爫',
+ '琢' => '琢',
+ '碑' => '碑',
+ '社' => '社',
+ '祉' => '祉',
+ '祈' => '祈',
+ '祐' => '祐',
+ '祖' => '祖',
+ '祝' => '祝',
+ '禍' => '禍',
+ '禎' => '禎',
+ '穀' => '穀',
+ '突' => '突',
+ '節' => '節',
+ '練' => '練',
+ '縉' => '縉',
+ '繁' => '繁',
+ '署' => '署',
+ '者' => '者',
+ '臭' => '臭',
+ '艹' => '艹',
+ '艹' => '艹',
+ '著' => '著',
+ '褐' => '褐',
+ '視' => '視',
+ '謁' => '謁',
+ '謹' => '謹',
+ '賓' => '賓',
+ '贈' => '贈',
+ '辶' => '辶',
+ '逸' => '逸',
+ '難' => '難',
+ '響' => '響',
+ '頻' => '頻',
+ '恵' => '恵',
+ '𤋮' => '𤋮',
+ '舘' => '舘',
+ '並' => '並',
+ '况' => '况',
+ '全' => '全',
+ '侀' => '侀',
+ '充' => '充',
+ '冀' => '冀',
+ '勇' => '勇',
+ '勺' => '勺',
+ '喝' => '喝',
+ '啕' => '啕',
+ '喙' => '喙',
+ '嗢' => '嗢',
+ '塚' => '塚',
+ '墳' => '墳',
+ '奄' => '奄',
+ '奔' => '奔',
+ '婢' => '婢',
+ '嬨' => '嬨',
+ '廒' => '廒',
+ '廙' => '廙',
+ '彩' => '彩',
+ '徭' => '徭',
+ '惘' => '惘',
+ '慎' => '慎',
+ '愈' => '愈',
+ '憎' => '憎',
+ '慠' => '慠',
+ '懲' => '懲',
+ '戴' => '戴',
+ '揄' => '揄',
+ '搜' => '搜',
+ '摒' => '摒',
+ '敖' => '敖',
+ '晴' => '晴',
+ '朗' => '朗',
+ '望' => '望',
+ '杖' => '杖',
+ '歹' => '歹',
+ '殺' => '殺',
+ '流' => '流',
+ '滛' => '滛',
+ '滋' => '滋',
+ '漢' => '漢',
+ '瀞' => '瀞',
+ '煮' => '煮',
+ '瞧' => '瞧',
+ '爵' => '爵',
+ '犯' => '犯',
+ '猪' => '猪',
+ '瑱' => '瑱',
+ '甆' => '甆',
+ '画' => '画',
+ '瘝' => '瘝',
+ '瘟' => '瘟',
+ '益' => '益',
+ '盛' => '盛',
+ '直' => '直',
+ '睊' => '睊',
+ '着' => '着',
+ '磌' => '磌',
+ '窱' => '窱',
+ '節' => '節',
+ '类' => '类',
+ '絛' => '絛',
+ '練' => '練',
+ '缾' => '缾',
+ '者' => '者',
+ '荒' => '荒',
+ '華' => '華',
+ '蝹' => '蝹',
+ '襁' => '襁',
+ '覆' => '覆',
+ '視' => '視',
+ '調' => '調',
+ '諸' => '諸',
+ '請' => '請',
+ '謁' => '謁',
+ '諾' => '諾',
+ '諭' => '諭',
+ '謹' => '謹',
+ '變' => '變',
+ '贈' => '贈',
+ '輸' => '輸',
+ '遲' => '遲',
+ '醙' => '醙',
+ '鉶' => '鉶',
+ '陼' => '陼',
+ '難' => '難',
+ '靖' => '靖',
+ '韛' => '韛',
+ '響' => '響',
+ '頋' => '頋',
+ '頻' => '頻',
+ '鬒' => '鬒',
+ '龜' => '龜',
+ '𢡊' => '𢡊',
+ '𢡄' => '𢡄',
+ '𣏕' => '𣏕',
+ '㮝' => '㮝',
+ '䀘' => '䀘',
+ '䀹' => '䀹',
+ '𥉉' => '𥉉',
+ '𥳐' => '𥳐',
+ '𧻓' => '𧻓',
+ '齃' => '齃',
+ '龎' => '龎',
+ 'יִ' => 'יִ',
+ 'ײַ' => 'ײַ',
+ 'שׁ' => 'שׁ',
+ 'שׂ' => 'שׂ',
+ 'שּׁ' => 'שּׁ',
+ 'שּׂ' => 'שּׂ',
+ 'אַ' => 'אַ',
+ 'אָ' => 'אָ',
+ 'אּ' => 'אּ',
+ 'בּ' => 'בּ',
+ 'גּ' => 'גּ',
+ 'דּ' => 'דּ',
+ 'הּ' => 'הּ',
+ 'וּ' => 'וּ',
+ 'זּ' => 'זּ',
+ 'טּ' => 'טּ',
+ 'יּ' => 'יּ',
+ 'ךּ' => 'ךּ',
+ 'כּ' => 'כּ',
+ 'לּ' => 'לּ',
+ 'מּ' => 'מּ',
+ 'נּ' => 'נּ',
+ 'סּ' => 'סּ',
+ 'ףּ' => 'ףּ',
+ 'פּ' => 'פּ',
+ 'צּ' => 'צּ',
+ 'קּ' => 'קּ',
+ 'רּ' => 'רּ',
+ 'שּ' => 'שּ',
+ 'תּ' => 'תּ',
+ 'וֹ' => 'וֹ',
+ 'בֿ' => 'בֿ',
+ 'כֿ' => 'כֿ',
+ 'פֿ' => 'פֿ',
+ '𑂚' => '𑂚',
+ '𑂜' => '𑂜',
+ '𑂫' => '𑂫',
+ '𑄮' => '𑄮',
+ '𑄯' => '𑄯',
+ '𑍋' => '𑍋',
+ '𑍌' => '𑍌',
+ '𑒻' => '𑒻',
+ '𑒼' => '𑒼',
+ '𑒾' => '𑒾',
+ '𑖺' => '𑖺',
+ '𑖻' => '𑖻',
+ '𑤸' => '𑤸',
+ '𝅗𝅥' => '𝅗𝅥',
+ '𝅘𝅥' => '𝅘𝅥',
+ '𝅘𝅥𝅮' => '𝅘𝅥𝅮',
+ '𝅘𝅥𝅯' => '𝅘𝅥𝅯',
+ '𝅘𝅥𝅰' => '𝅘𝅥𝅰',
+ '𝅘𝅥𝅱' => '𝅘𝅥𝅱',
+ '𝅘𝅥𝅲' => '𝅘𝅥𝅲',
+ '𝆹𝅥' => '𝆹𝅥',
+ '𝆺𝅥' => '𝆺𝅥',
+ '𝆹𝅥𝅮' => '𝆹𝅥𝅮',
+ '𝆺𝅥𝅮' => '𝆺𝅥𝅮',
+ '𝆹𝅥𝅯' => '𝆹𝅥𝅯',
+ '𝆺𝅥𝅯' => '𝆺𝅥𝅯',
+ '丽' => '丽',
+ '丸' => '丸',
+ '乁' => '乁',
+ '𠄢' => '𠄢',
+ '你' => '你',
+ '侮' => '侮',
+ '侻' => '侻',
+ '倂' => '倂',
+ '偺' => '偺',
+ '備' => '備',
+ '僧' => '僧',
+ '像' => '像',
+ '㒞' => '㒞',
+ '𠘺' => '𠘺',
+ '免' => '免',
+ '兔' => '兔',
+ '兤' => '兤',
+ '具' => '具',
+ '𠔜' => '𠔜',
+ '㒹' => '㒹',
+ '內' => '內',
+ '再' => '再',
+ '𠕋' => '𠕋',
+ '冗' => '冗',
+ '冤' => '冤',
+ '仌' => '仌',
+ '冬' => '冬',
+ '况' => '况',
+ '𩇟' => '𩇟',
+ '凵' => '凵',
+ '刃' => '刃',
+ '㓟' => '㓟',
+ '刻' => '刻',
+ '剆' => '剆',
+ '割' => '割',
+ '剷' => '剷',
+ '㔕' => '㔕',
+ '勇' => '勇',
+ '勉' => '勉',
+ '勤' => '勤',
+ '勺' => '勺',
+ '包' => '包',
+ '匆' => '匆',
+ '北' => '北',
+ '卉' => '卉',
+ '卑' => '卑',
+ '博' => '博',
+ '即' => '即',
+ '卽' => '卽',
+ '卿' => '卿',
+ '卿' => '卿',
+ '卿' => '卿',
+ '𠨬' => '𠨬',
+ '灰' => '灰',
+ '及' => '及',
+ '叟' => '叟',
+ '𠭣' => '𠭣',
+ '叫' => '叫',
+ '叱' => '叱',
+ '吆' => '吆',
+ '咞' => '咞',
+ '吸' => '吸',
+ '呈' => '呈',
+ '周' => '周',
+ '咢' => '咢',
+ '哶' => '哶',
+ '唐' => '唐',
+ '啓' => '啓',
+ '啣' => '啣',
+ '善' => '善',
+ '善' => '善',
+ '喙' => '喙',
+ '喫' => '喫',
+ '喳' => '喳',
+ '嗂' => '嗂',
+ '圖' => '圖',
+ '嘆' => '嘆',
+ '圗' => '圗',
+ '噑' => '噑',
+ '噴' => '噴',
+ '切' => '切',
+ '壮' => '壮',
+ '城' => '城',
+ '埴' => '埴',
+ '堍' => '堍',
+ '型' => '型',
+ '堲' => '堲',
+ '報' => '報',
+ '墬' => '墬',
+ '𡓤' => '𡓤',
+ '売' => '売',
+ '壷' => '壷',
+ '夆' => '夆',
+ '多' => '多',
+ '夢' => '夢',
+ '奢' => '奢',
+ '𡚨' => '𡚨',
+ '𡛪' => '𡛪',
+ '姬' => '姬',
+ '娛' => '娛',
+ '娧' => '娧',
+ '姘' => '姘',
+ '婦' => '婦',
+ '㛮' => '㛮',
+ '㛼' => '㛼',
+ '嬈' => '嬈',
+ '嬾' => '嬾',
+ '嬾' => '嬾',
+ '𡧈' => '𡧈',
+ '寃' => '寃',
+ '寘' => '寘',
+ '寧' => '寧',
+ '寳' => '寳',
+ '𡬘' => '𡬘',
+ '寿' => '寿',
+ '将' => '将',
+ '当' => '当',
+ '尢' => '尢',
+ '㞁' => '㞁',
+ '屠' => '屠',
+ '屮' => '屮',
+ '峀' => '峀',
+ '岍' => '岍',
+ '𡷤' => '𡷤',
+ '嵃' => '嵃',
+ '𡷦' => '𡷦',
+ '嵮' => '嵮',
+ '嵫' => '嵫',
+ '嵼' => '嵼',
+ '巡' => '巡',
+ '巢' => '巢',
+ '㠯' => '㠯',
+ '巽' => '巽',
+ '帨' => '帨',
+ '帽' => '帽',
+ '幩' => '幩',
+ '㡢' => '㡢',
+ '𢆃' => '𢆃',
+ '㡼' => '㡼',
+ '庰' => '庰',
+ '庳' => '庳',
+ '庶' => '庶',
+ '廊' => '廊',
+ '𪎒' => '𪎒',
+ '廾' => '廾',
+ '𢌱' => '𢌱',
+ '𢌱' => '𢌱',
+ '舁' => '舁',
+ '弢' => '弢',
+ '弢' => '弢',
+ '㣇' => '㣇',
+ '𣊸' => '𣊸',
+ '𦇚' => '𦇚',
+ '形' => '形',
+ '彫' => '彫',
+ '㣣' => '㣣',
+ '徚' => '徚',
+ '忍' => '忍',
+ '志' => '志',
+ '忹' => '忹',
+ '悁' => '悁',
+ '㤺' => '㤺',
+ '㤜' => '㤜',
+ '悔' => '悔',
+ '𢛔' => '𢛔',
+ '惇' => '惇',
+ '慈' => '慈',
+ '慌' => '慌',
+ '慎' => '慎',
+ '慌' => '慌',
+ '慺' => '慺',
+ '憎' => '憎',
+ '憲' => '憲',
+ '憤' => '憤',
+ '憯' => '憯',
+ '懞' => '懞',
+ '懲' => '懲',
+ '懶' => '懶',
+ '成' => '成',
+ '戛' => '戛',
+ '扝' => '扝',
+ '抱' => '抱',
+ '拔' => '拔',
+ '捐' => '捐',
+ '𢬌' => '𢬌',
+ '挽' => '挽',
+ '拼' => '拼',
+ '捨' => '捨',
+ '掃' => '掃',
+ '揤' => '揤',
+ '𢯱' => '𢯱',
+ '搢' => '搢',
+ '揅' => '揅',
+ '掩' => '掩',
+ '㨮' => '㨮',
+ '摩' => '摩',
+ '摾' => '摾',
+ '撝' => '撝',
+ '摷' => '摷',
+ '㩬' => '㩬',
+ '敏' => '敏',
+ '敬' => '敬',
+ '𣀊' => '𣀊',
+ '旣' => '旣',
+ '書' => '書',
+ '晉' => '晉',
+ '㬙' => '㬙',
+ '暑' => '暑',
+ '㬈' => '㬈',
+ '㫤' => '㫤',
+ '冒' => '冒',
+ '冕' => '冕',
+ '最' => '最',
+ '暜' => '暜',
+ '肭' => '肭',
+ '䏙' => '䏙',
+ '朗' => '朗',
+ '望' => '望',
+ '朡' => '朡',
+ '杞' => '杞',
+ '杓' => '杓',
+ '𣏃' => '𣏃',
+ '㭉' => '㭉',
+ '柺' => '柺',
+ '枅' => '枅',
+ '桒' => '桒',
+ '梅' => '梅',
+ '𣑭' => '𣑭',
+ '梎' => '梎',
+ '栟' => '栟',
+ '椔' => '椔',
+ '㮝' => '㮝',
+ '楂' => '楂',
+ '榣' => '榣',
+ '槪' => '槪',
+ '檨' => '檨',
+ '𣚣' => '𣚣',
+ '櫛' => '櫛',
+ '㰘' => '㰘',
+ '次' => '次',
+ '𣢧' => '𣢧',
+ '歔' => '歔',
+ '㱎' => '㱎',
+ '歲' => '歲',
+ '殟' => '殟',
+ '殺' => '殺',
+ '殻' => '殻',
+ '𣪍' => '𣪍',
+ '𡴋' => '𡴋',
+ '𣫺' => '𣫺',
+ '汎' => '汎',
+ '𣲼' => '𣲼',
+ '沿' => '沿',
+ '泍' => '泍',
+ '汧' => '汧',
+ '洖' => '洖',
+ '派' => '派',
+ '海' => '海',
+ '流' => '流',
+ '浩' => '浩',
+ '浸' => '浸',
+ '涅' => '涅',
+ '𣴞' => '𣴞',
+ '洴' => '洴',
+ '港' => '港',
+ '湮' => '湮',
+ '㴳' => '㴳',
+ '滋' => '滋',
+ '滇' => '滇',
+ '𣻑' => '𣻑',
+ '淹' => '淹',
+ '潮' => '潮',
+ '𣽞' => '𣽞',
+ '𣾎' => '𣾎',
+ '濆' => '濆',
+ '瀹' => '瀹',
+ '瀞' => '瀞',
+ '瀛' => '瀛',
+ '㶖' => '㶖',
+ '灊' => '灊',
+ '災' => '災',
+ '灷' => '灷',
+ '炭' => '炭',
+ '𠔥' => '𠔥',
+ '煅' => '煅',
+ '𤉣' => '𤉣',
+ '熜' => '熜',
+ '𤎫' => '𤎫',
+ '爨' => '爨',
+ '爵' => '爵',
+ '牐' => '牐',
+ '𤘈' => '𤘈',
+ '犀' => '犀',
+ '犕' => '犕',
+ '𤜵' => '𤜵',
+ '𤠔' => '𤠔',
+ '獺' => '獺',
+ '王' => '王',
+ '㺬' => '㺬',
+ '玥' => '玥',
+ '㺸' => '㺸',
+ '㺸' => '㺸',
+ '瑇' => '瑇',
+ '瑜' => '瑜',
+ '瑱' => '瑱',
+ '璅' => '璅',
+ '瓊' => '瓊',
+ '㼛' => '㼛',
+ '甤' => '甤',
+ '𤰶' => '𤰶',
+ '甾' => '甾',
+ '𤲒' => '𤲒',
+ '異' => '異',
+ '𢆟' => '𢆟',
+ '瘐' => '瘐',
+ '𤾡' => '𤾡',
+ '𤾸' => '𤾸',
+ '𥁄' => '𥁄',
+ '㿼' => '㿼',
+ '䀈' => '䀈',
+ '直' => '直',
+ '𥃳' => '𥃳',
+ '𥃲' => '𥃲',
+ '𥄙' => '𥄙',
+ '𥄳' => '𥄳',
+ '眞' => '眞',
+ '真' => '真',
+ '真' => '真',
+ '睊' => '睊',
+ '䀹' => '䀹',
+ '瞋' => '瞋',
+ '䁆' => '䁆',
+ '䂖' => '䂖',
+ '𥐝' => '𥐝',
+ '硎' => '硎',
+ '碌' => '碌',
+ '磌' => '磌',
+ '䃣' => '䃣',
+ '𥘦' => '𥘦',
+ '祖' => '祖',
+ '𥚚' => '𥚚',
+ '𥛅' => '𥛅',
+ '福' => '福',
+ '秫' => '秫',
+ '䄯' => '䄯',
+ '穀' => '穀',
+ '穊' => '穊',
+ '穏' => '穏',
+ '𥥼' => '𥥼',
+ '𥪧' => '𥪧',
+ '𥪧' => '𥪧',
+ '竮' => '竮',
+ '䈂' => '䈂',
+ '𥮫' => '𥮫',
+ '篆' => '篆',
+ '築' => '築',
+ '䈧' => '䈧',
+ '𥲀' => '𥲀',
+ '糒' => '糒',
+ '䊠' => '䊠',
+ '糨' => '糨',
+ '糣' => '糣',
+ '紀' => '紀',
+ '𥾆' => '𥾆',
+ '絣' => '絣',
+ '䌁' => '䌁',
+ '緇' => '緇',
+ '縂' => '縂',
+ '繅' => '繅',
+ '䌴' => '䌴',
+ '𦈨' => '𦈨',
+ '𦉇' => '𦉇',
+ '䍙' => '䍙',
+ '𦋙' => '𦋙',
+ '罺' => '罺',
+ '𦌾' => '𦌾',
+ '羕' => '羕',
+ '翺' => '翺',
+ '者' => '者',
+ '𦓚' => '𦓚',
+ '𦔣' => '𦔣',
+ '聠' => '聠',
+ '𦖨' => '𦖨',
+ '聰' => '聰',
+ '𣍟' => '𣍟',
+ '䏕' => '䏕',
+ '育' => '育',
+ '脃' => '脃',
+ '䐋' => '䐋',
+ '脾' => '脾',
+ '媵' => '媵',
+ '𦞧' => '𦞧',
+ '𦞵' => '𦞵',
+ '𣎓' => '𣎓',
+ '𣎜' => '𣎜',
+ '舁' => '舁',
+ '舄' => '舄',
+ '辞' => '辞',
+ '䑫' => '䑫',
+ '芑' => '芑',
+ '芋' => '芋',
+ '芝' => '芝',
+ '劳' => '劳',
+ '花' => '花',
+ '芳' => '芳',
+ '芽' => '芽',
+ '苦' => '苦',
+ '𦬼' => '𦬼',
+ '若' => '若',
+ '茝' => '茝',
+ '荣' => '荣',
+ '莭' => '莭',
+ '茣' => '茣',
+ '莽' => '莽',
+ '菧' => '菧',
+ '著' => '著',
+ '荓' => '荓',
+ '菊' => '菊',
+ '菌' => '菌',
+ '菜' => '菜',
+ '𦰶' => '𦰶',
+ '𦵫' => '𦵫',
+ '𦳕' => '𦳕',
+ '䔫' => '䔫',
+ '蓱' => '蓱',
+ '蓳' => '蓳',
+ '蔖' => '蔖',
+ '𧏊' => '𧏊',
+ '蕤' => '蕤',
+ '𦼬' => '𦼬',
+ '䕝' => '䕝',
+ '䕡' => '䕡',
+ '𦾱' => '𦾱',
+ '𧃒' => '𧃒',
+ '䕫' => '䕫',
+ '虐' => '虐',
+ '虜' => '虜',
+ '虧' => '虧',
+ '虩' => '虩',
+ '蚩' => '蚩',
+ '蚈' => '蚈',
+ '蜎' => '蜎',
+ '蛢' => '蛢',
+ '蝹' => '蝹',
+ '蜨' => '蜨',
+ '蝫' => '蝫',
+ '螆' => '螆',
+ '䗗' => '䗗',
+ '蟡' => '蟡',
+ '蠁' => '蠁',
+ '䗹' => '䗹',
+ '衠' => '衠',
+ '衣' => '衣',
+ '𧙧' => '𧙧',
+ '裗' => '裗',
+ '裞' => '裞',
+ '䘵' => '䘵',
+ '裺' => '裺',
+ '㒻' => '㒻',
+ '𧢮' => '𧢮',
+ '𧥦' => '𧥦',
+ '䚾' => '䚾',
+ '䛇' => '䛇',
+ '誠' => '誠',
+ '諭' => '諭',
+ '變' => '變',
+ '豕' => '豕',
+ '𧲨' => '𧲨',
+ '貫' => '貫',
+ '賁' => '賁',
+ '贛' => '贛',
+ '起' => '起',
+ '𧼯' => '𧼯',
+ '𠠄' => '𠠄',
+ '跋' => '跋',
+ '趼' => '趼',
+ '跰' => '跰',
+ '𠣞' => '𠣞',
+ '軔' => '軔',
+ '輸' => '輸',
+ '𨗒' => '𨗒',
+ '𨗭' => '𨗭',
+ '邔' => '邔',
+ '郱' => '郱',
+ '鄑' => '鄑',
+ '𨜮' => '𨜮',
+ '鄛' => '鄛',
+ '鈸' => '鈸',
+ '鋗' => '鋗',
+ '鋘' => '鋘',
+ '鉼' => '鉼',
+ '鏹' => '鏹',
+ '鐕' => '鐕',
+ '𨯺' => '𨯺',
+ '開' => '開',
+ '䦕' => '䦕',
+ '閷' => '閷',
+ '𨵷' => '𨵷',
+ '䧦' => '䧦',
+ '雃' => '雃',
+ '嶲' => '嶲',
+ '霣' => '霣',
+ '𩅅' => '𩅅',
+ '𩈚' => '𩈚',
+ '䩮' => '䩮',
+ '䩶' => '䩶',
+ '韠' => '韠',
+ '𩐊' => '𩐊',
+ '䪲' => '䪲',
+ '𩒖' => '𩒖',
+ '頋' => '頋',
+ '頋' => '頋',
+ '頩' => '頩',
+ '𩖶' => '𩖶',
+ '飢' => '飢',
+ '䬳' => '䬳',
+ '餩' => '餩',
+ '馧' => '馧',
+ '駂' => '駂',
+ '駾' => '駾',
+ '䯎' => '䯎',
+ '𩬰' => '𩬰',
+ '鬒' => '鬒',
+ '鱀' => '鱀',
+ '鳽' => '鳽',
+ '䳎' => '䳎',
+ '䳭' => '䳭',
+ '鵧' => '鵧',
+ '𪃎' => '𪃎',
+ '䳸' => '䳸',
+ '𪄅' => '𪄅',
+ '𪈎' => '𪈎',
+ '𪊑' => '𪊑',
+ '麻' => '麻',
+ '䵖' => '䵖',
+ '黹' => '黹',
+ '黾' => '黾',
+ '鼅' => '鼅',
+ '鼏' => '鼏',
+ '鼖' => '鼖',
+ '鼻' => '鼻',
+ '𪘀' => '𪘀',
+);
diff --git a/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php b/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php
new file mode 100644
index 000000000..ec90f36eb
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php
@@ -0,0 +1,876 @@
+ 230,
+ '́' => 230,
+ '̂' => 230,
+ '̃' => 230,
+ '̄' => 230,
+ '̅' => 230,
+ '̆' => 230,
+ '̇' => 230,
+ '̈' => 230,
+ '̉' => 230,
+ '̊' => 230,
+ '̋' => 230,
+ '̌' => 230,
+ '̍' => 230,
+ '̎' => 230,
+ '̏' => 230,
+ '̐' => 230,
+ '̑' => 230,
+ '̒' => 230,
+ '̓' => 230,
+ '̔' => 230,
+ '̕' => 232,
+ '̖' => 220,
+ '̗' => 220,
+ '̘' => 220,
+ '̙' => 220,
+ '̚' => 232,
+ '̛' => 216,
+ '̜' => 220,
+ '̝' => 220,
+ '̞' => 220,
+ '̟' => 220,
+ '̠' => 220,
+ '̡' => 202,
+ '̢' => 202,
+ '̣' => 220,
+ '̤' => 220,
+ '̥' => 220,
+ '̦' => 220,
+ '̧' => 202,
+ '̨' => 202,
+ '̩' => 220,
+ '̪' => 220,
+ '̫' => 220,
+ '̬' => 220,
+ '̭' => 220,
+ '̮' => 220,
+ '̯' => 220,
+ '̰' => 220,
+ '̱' => 220,
+ '̲' => 220,
+ '̳' => 220,
+ '̴' => 1,
+ '̵' => 1,
+ '̶' => 1,
+ '̷' => 1,
+ '̸' => 1,
+ '̹' => 220,
+ '̺' => 220,
+ '̻' => 220,
+ '̼' => 220,
+ '̽' => 230,
+ '̾' => 230,
+ '̿' => 230,
+ '̀' => 230,
+ '́' => 230,
+ '͂' => 230,
+ '̓' => 230,
+ '̈́' => 230,
+ 'ͅ' => 240,
+ '͆' => 230,
+ '͇' => 220,
+ '͈' => 220,
+ '͉' => 220,
+ '͊' => 230,
+ '͋' => 230,
+ '͌' => 230,
+ '͍' => 220,
+ '͎' => 220,
+ '͐' => 230,
+ '͑' => 230,
+ '͒' => 230,
+ '͓' => 220,
+ '͔' => 220,
+ '͕' => 220,
+ '͖' => 220,
+ '͗' => 230,
+ '͘' => 232,
+ '͙' => 220,
+ '͚' => 220,
+ '͛' => 230,
+ '͜' => 233,
+ '͝' => 234,
+ '͞' => 234,
+ '͟' => 233,
+ '͠' => 234,
+ '͡' => 234,
+ '͢' => 233,
+ 'ͣ' => 230,
+ 'ͤ' => 230,
+ 'ͥ' => 230,
+ 'ͦ' => 230,
+ 'ͧ' => 230,
+ 'ͨ' => 230,
+ 'ͩ' => 230,
+ 'ͪ' => 230,
+ 'ͫ' => 230,
+ 'ͬ' => 230,
+ 'ͭ' => 230,
+ 'ͮ' => 230,
+ 'ͯ' => 230,
+ '҃' => 230,
+ '҄' => 230,
+ '҅' => 230,
+ '҆' => 230,
+ '҇' => 230,
+ '֑' => 220,
+ '֒' => 230,
+ '֓' => 230,
+ '֔' => 230,
+ '֕' => 230,
+ '֖' => 220,
+ '֗' => 230,
+ '֘' => 230,
+ '֙' => 230,
+ '֚' => 222,
+ '֛' => 220,
+ '֜' => 230,
+ '֝' => 230,
+ '֞' => 230,
+ '֟' => 230,
+ '֠' => 230,
+ '֡' => 230,
+ '֢' => 220,
+ '֣' => 220,
+ '֤' => 220,
+ '֥' => 220,
+ '֦' => 220,
+ '֧' => 220,
+ '֨' => 230,
+ '֩' => 230,
+ '֪' => 220,
+ '֫' => 230,
+ '֬' => 230,
+ '֭' => 222,
+ '֮' => 228,
+ '֯' => 230,
+ 'ְ' => 10,
+ 'ֱ' => 11,
+ 'ֲ' => 12,
+ 'ֳ' => 13,
+ 'ִ' => 14,
+ 'ֵ' => 15,
+ 'ֶ' => 16,
+ 'ַ' => 17,
+ 'ָ' => 18,
+ 'ֹ' => 19,
+ 'ֺ' => 19,
+ 'ֻ' => 20,
+ 'ּ' => 21,
+ 'ֽ' => 22,
+ 'ֿ' => 23,
+ 'ׁ' => 24,
+ 'ׂ' => 25,
+ 'ׄ' => 230,
+ 'ׅ' => 220,
+ 'ׇ' => 18,
+ 'ؐ' => 230,
+ 'ؑ' => 230,
+ 'ؒ' => 230,
+ 'ؓ' => 230,
+ 'ؔ' => 230,
+ 'ؕ' => 230,
+ 'ؖ' => 230,
+ 'ؗ' => 230,
+ 'ؘ' => 30,
+ 'ؙ' => 31,
+ 'ؚ' => 32,
+ 'ً' => 27,
+ 'ٌ' => 28,
+ 'ٍ' => 29,
+ 'َ' => 30,
+ 'ُ' => 31,
+ 'ِ' => 32,
+ 'ّ' => 33,
+ 'ْ' => 34,
+ 'ٓ' => 230,
+ 'ٔ' => 230,
+ 'ٕ' => 220,
+ 'ٖ' => 220,
+ 'ٗ' => 230,
+ '٘' => 230,
+ 'ٙ' => 230,
+ 'ٚ' => 230,
+ 'ٛ' => 230,
+ 'ٜ' => 220,
+ 'ٝ' => 230,
+ 'ٞ' => 230,
+ 'ٟ' => 220,
+ 'ٰ' => 35,
+ 'ۖ' => 230,
+ 'ۗ' => 230,
+ 'ۘ' => 230,
+ 'ۙ' => 230,
+ 'ۚ' => 230,
+ 'ۛ' => 230,
+ 'ۜ' => 230,
+ '۟' => 230,
+ '۠' => 230,
+ 'ۡ' => 230,
+ 'ۢ' => 230,
+ 'ۣ' => 220,
+ 'ۤ' => 230,
+ 'ۧ' => 230,
+ 'ۨ' => 230,
+ '۪' => 220,
+ '۫' => 230,
+ '۬' => 230,
+ 'ۭ' => 220,
+ 'ܑ' => 36,
+ 'ܰ' => 230,
+ 'ܱ' => 220,
+ 'ܲ' => 230,
+ 'ܳ' => 230,
+ 'ܴ' => 220,
+ 'ܵ' => 230,
+ 'ܶ' => 230,
+ 'ܷ' => 220,
+ 'ܸ' => 220,
+ 'ܹ' => 220,
+ 'ܺ' => 230,
+ 'ܻ' => 220,
+ 'ܼ' => 220,
+ 'ܽ' => 230,
+ 'ܾ' => 220,
+ 'ܿ' => 230,
+ '݀' => 230,
+ '݁' => 230,
+ '݂' => 220,
+ '݃' => 230,
+ '݄' => 220,
+ '݅' => 230,
+ '݆' => 220,
+ '݇' => 230,
+ '݈' => 220,
+ '݉' => 230,
+ '݊' => 230,
+ '߫' => 230,
+ '߬' => 230,
+ '߭' => 230,
+ '߮' => 230,
+ '߯' => 230,
+ '߰' => 230,
+ '߱' => 230,
+ '߲' => 220,
+ '߳' => 230,
+ '߽' => 220,
+ 'ࠖ' => 230,
+ 'ࠗ' => 230,
+ '࠘' => 230,
+ '࠙' => 230,
+ 'ࠛ' => 230,
+ 'ࠜ' => 230,
+ 'ࠝ' => 230,
+ 'ࠞ' => 230,
+ 'ࠟ' => 230,
+ 'ࠠ' => 230,
+ 'ࠡ' => 230,
+ 'ࠢ' => 230,
+ 'ࠣ' => 230,
+ 'ࠥ' => 230,
+ 'ࠦ' => 230,
+ 'ࠧ' => 230,
+ 'ࠩ' => 230,
+ 'ࠪ' => 230,
+ 'ࠫ' => 230,
+ 'ࠬ' => 230,
+ '࠭' => 230,
+ '࡙' => 220,
+ '࡚' => 220,
+ '࡛' => 220,
+ '࣓' => 220,
+ 'ࣔ' => 230,
+ 'ࣕ' => 230,
+ 'ࣖ' => 230,
+ 'ࣗ' => 230,
+ 'ࣘ' => 230,
+ 'ࣙ' => 230,
+ 'ࣚ' => 230,
+ 'ࣛ' => 230,
+ 'ࣜ' => 230,
+ 'ࣝ' => 230,
+ 'ࣞ' => 230,
+ 'ࣟ' => 230,
+ '࣠' => 230,
+ '࣡' => 230,
+ 'ࣣ' => 220,
+ 'ࣤ' => 230,
+ 'ࣥ' => 230,
+ 'ࣦ' => 220,
+ 'ࣧ' => 230,
+ 'ࣨ' => 230,
+ 'ࣩ' => 220,
+ '࣪' => 230,
+ '࣫' => 230,
+ '࣬' => 230,
+ '࣭' => 220,
+ '࣮' => 220,
+ '࣯' => 220,
+ 'ࣰ' => 27,
+ 'ࣱ' => 28,
+ 'ࣲ' => 29,
+ 'ࣳ' => 230,
+ 'ࣴ' => 230,
+ 'ࣵ' => 230,
+ 'ࣶ' => 220,
+ 'ࣷ' => 230,
+ 'ࣸ' => 230,
+ 'ࣹ' => 220,
+ 'ࣺ' => 220,
+ 'ࣻ' => 230,
+ 'ࣼ' => 230,
+ 'ࣽ' => 230,
+ 'ࣾ' => 230,
+ 'ࣿ' => 230,
+ '़' => 7,
+ '्' => 9,
+ '॑' => 230,
+ '॒' => 220,
+ '॓' => 230,
+ '॔' => 230,
+ '়' => 7,
+ '্' => 9,
+ '৾' => 230,
+ '਼' => 7,
+ '੍' => 9,
+ '઼' => 7,
+ '્' => 9,
+ '଼' => 7,
+ '୍' => 9,
+ '்' => 9,
+ '్' => 9,
+ 'ౕ' => 84,
+ 'ౖ' => 91,
+ '಼' => 7,
+ '್' => 9,
+ '഻' => 9,
+ '഼' => 9,
+ '്' => 9,
+ '්' => 9,
+ 'ุ' => 103,
+ 'ู' => 103,
+ 'ฺ' => 9,
+ '่' => 107,
+ '้' => 107,
+ '๊' => 107,
+ '๋' => 107,
+ 'ຸ' => 118,
+ 'ູ' => 118,
+ '຺' => 9,
+ '່' => 122,
+ '້' => 122,
+ '໊' => 122,
+ '໋' => 122,
+ '༘' => 220,
+ '༙' => 220,
+ '༵' => 220,
+ '༷' => 220,
+ '༹' => 216,
+ 'ཱ' => 129,
+ 'ི' => 130,
+ 'ུ' => 132,
+ 'ེ' => 130,
+ 'ཻ' => 130,
+ 'ོ' => 130,
+ 'ཽ' => 130,
+ 'ྀ' => 130,
+ 'ྂ' => 230,
+ 'ྃ' => 230,
+ '྄' => 9,
+ '྆' => 230,
+ '྇' => 230,
+ '࿆' => 220,
+ '့' => 7,
+ '္' => 9,
+ '်' => 9,
+ 'ႍ' => 220,
+ '፝' => 230,
+ '፞' => 230,
+ '፟' => 230,
+ '᜔' => 9,
+ '᜴' => 9,
+ '្' => 9,
+ '៝' => 230,
+ 'ᢩ' => 228,
+ '᤹' => 222,
+ '᤺' => 230,
+ '᤻' => 220,
+ 'ᨗ' => 230,
+ 'ᨘ' => 220,
+ '᩠' => 9,
+ '᩵' => 230,
+ '᩶' => 230,
+ '᩷' => 230,
+ '᩸' => 230,
+ '᩹' => 230,
+ '᩺' => 230,
+ '᩻' => 230,
+ '᩼' => 230,
+ '᩿' => 220,
+ '᪰' => 230,
+ '᪱' => 230,
+ '᪲' => 230,
+ '᪳' => 230,
+ '᪴' => 230,
+ '᪵' => 220,
+ '᪶' => 220,
+ '᪷' => 220,
+ '᪸' => 220,
+ '᪹' => 220,
+ '᪺' => 220,
+ '᪻' => 230,
+ '᪼' => 230,
+ '᪽' => 220,
+ 'ᪿ' => 220,
+ 'ᫀ' => 220,
+ '᬴' => 7,
+ '᭄' => 9,
+ '᭫' => 230,
+ '᭬' => 220,
+ '᭭' => 230,
+ '᭮' => 230,
+ '᭯' => 230,
+ '᭰' => 230,
+ '᭱' => 230,
+ '᭲' => 230,
+ '᭳' => 230,
+ '᮪' => 9,
+ '᮫' => 9,
+ '᯦' => 7,
+ '᯲' => 9,
+ '᯳' => 9,
+ '᰷' => 7,
+ '᳐' => 230,
+ '᳑' => 230,
+ '᳒' => 230,
+ '᳔' => 1,
+ '᳕' => 220,
+ '᳖' => 220,
+ '᳗' => 220,
+ '᳘' => 220,
+ '᳙' => 220,
+ '᳚' => 230,
+ '᳛' => 230,
+ '᳜' => 220,
+ '᳝' => 220,
+ '᳞' => 220,
+ '᳟' => 220,
+ '᳠' => 230,
+ '᳢' => 1,
+ '᳣' => 1,
+ '᳤' => 1,
+ '᳥' => 1,
+ '᳦' => 1,
+ '᳧' => 1,
+ '᳨' => 1,
+ '᳭' => 220,
+ '᳴' => 230,
+ '᳸' => 230,
+ '᳹' => 230,
+ '᷀' => 230,
+ '᷁' => 230,
+ '᷂' => 220,
+ '᷃' => 230,
+ '᷄' => 230,
+ '᷅' => 230,
+ '᷆' => 230,
+ '᷇' => 230,
+ '᷈' => 230,
+ '᷉' => 230,
+ '᷊' => 220,
+ '᷋' => 230,
+ '᷌' => 230,
+ '᷍' => 234,
+ '᷎' => 214,
+ '᷏' => 220,
+ '᷐' => 202,
+ '᷑' => 230,
+ '᷒' => 230,
+ 'ᷓ' => 230,
+ 'ᷔ' => 230,
+ 'ᷕ' => 230,
+ 'ᷖ' => 230,
+ 'ᷗ' => 230,
+ 'ᷘ' => 230,
+ 'ᷙ' => 230,
+ 'ᷚ' => 230,
+ 'ᷛ' => 230,
+ 'ᷜ' => 230,
+ 'ᷝ' => 230,
+ 'ᷞ' => 230,
+ 'ᷟ' => 230,
+ 'ᷠ' => 230,
+ 'ᷡ' => 230,
+ 'ᷢ' => 230,
+ 'ᷣ' => 230,
+ 'ᷤ' => 230,
+ 'ᷥ' => 230,
+ 'ᷦ' => 230,
+ 'ᷧ' => 230,
+ 'ᷨ' => 230,
+ 'ᷩ' => 230,
+ 'ᷪ' => 230,
+ 'ᷫ' => 230,
+ 'ᷬ' => 230,
+ 'ᷭ' => 230,
+ 'ᷮ' => 230,
+ 'ᷯ' => 230,
+ 'ᷰ' => 230,
+ 'ᷱ' => 230,
+ 'ᷲ' => 230,
+ 'ᷳ' => 230,
+ 'ᷴ' => 230,
+ '᷵' => 230,
+ '᷶' => 232,
+ '᷷' => 228,
+ '᷸' => 228,
+ '᷹' => 220,
+ '᷻' => 230,
+ '᷼' => 233,
+ '᷽' => 220,
+ '᷾' => 230,
+ '᷿' => 220,
+ '⃐' => 230,
+ '⃑' => 230,
+ '⃒' => 1,
+ '⃓' => 1,
+ '⃔' => 230,
+ '⃕' => 230,
+ '⃖' => 230,
+ '⃗' => 230,
+ '⃘' => 1,
+ '⃙' => 1,
+ '⃚' => 1,
+ '⃛' => 230,
+ '⃜' => 230,
+ '⃡' => 230,
+ '⃥' => 1,
+ '⃦' => 1,
+ '⃧' => 230,
+ '⃨' => 220,
+ '⃩' => 230,
+ '⃪' => 1,
+ '⃫' => 1,
+ '⃬' => 220,
+ '⃭' => 220,
+ '⃮' => 220,
+ '⃯' => 220,
+ '⃰' => 230,
+ '⳯' => 230,
+ '⳰' => 230,
+ '⳱' => 230,
+ '⵿' => 9,
+ 'ⷠ' => 230,
+ 'ⷡ' => 230,
+ 'ⷢ' => 230,
+ 'ⷣ' => 230,
+ 'ⷤ' => 230,
+ 'ⷥ' => 230,
+ 'ⷦ' => 230,
+ 'ⷧ' => 230,
+ 'ⷨ' => 230,
+ 'ⷩ' => 230,
+ 'ⷪ' => 230,
+ 'ⷫ' => 230,
+ 'ⷬ' => 230,
+ 'ⷭ' => 230,
+ 'ⷮ' => 230,
+ 'ⷯ' => 230,
+ 'ⷰ' => 230,
+ 'ⷱ' => 230,
+ 'ⷲ' => 230,
+ 'ⷳ' => 230,
+ 'ⷴ' => 230,
+ 'ⷵ' => 230,
+ 'ⷶ' => 230,
+ 'ⷷ' => 230,
+ 'ⷸ' => 230,
+ 'ⷹ' => 230,
+ 'ⷺ' => 230,
+ 'ⷻ' => 230,
+ 'ⷼ' => 230,
+ 'ⷽ' => 230,
+ 'ⷾ' => 230,
+ 'ⷿ' => 230,
+ '〪' => 218,
+ '〫' => 228,
+ '〬' => 232,
+ '〭' => 222,
+ '〮' => 224,
+ '〯' => 224,
+ '゙' => 8,
+ '゚' => 8,
+ '꙯' => 230,
+ 'ꙴ' => 230,
+ 'ꙵ' => 230,
+ 'ꙶ' => 230,
+ 'ꙷ' => 230,
+ 'ꙸ' => 230,
+ 'ꙹ' => 230,
+ 'ꙺ' => 230,
+ 'ꙻ' => 230,
+ '꙼' => 230,
+ '꙽' => 230,
+ 'ꚞ' => 230,
+ 'ꚟ' => 230,
+ '꛰' => 230,
+ '꛱' => 230,
+ '꠆' => 9,
+ '꠬' => 9,
+ '꣄' => 9,
+ '꣠' => 230,
+ '꣡' => 230,
+ '꣢' => 230,
+ '꣣' => 230,
+ '꣤' => 230,
+ '꣥' => 230,
+ '꣦' => 230,
+ '꣧' => 230,
+ '꣨' => 230,
+ '꣩' => 230,
+ '꣪' => 230,
+ '꣫' => 230,
+ '꣬' => 230,
+ '꣭' => 230,
+ '꣮' => 230,
+ '꣯' => 230,
+ '꣰' => 230,
+ '꣱' => 230,
+ '꤫' => 220,
+ '꤬' => 220,
+ '꤭' => 220,
+ '꥓' => 9,
+ '꦳' => 7,
+ '꧀' => 9,
+ 'ꪰ' => 230,
+ 'ꪲ' => 230,
+ 'ꪳ' => 230,
+ 'ꪴ' => 220,
+ 'ꪷ' => 230,
+ 'ꪸ' => 230,
+ 'ꪾ' => 230,
+ '꪿' => 230,
+ '꫁' => 230,
+ '꫶' => 9,
+ '꯭' => 9,
+ 'ﬞ' => 26,
+ '︠' => 230,
+ '︡' => 230,
+ '︢' => 230,
+ '︣' => 230,
+ '︤' => 230,
+ '︥' => 230,
+ '︦' => 230,
+ '︧' => 220,
+ '︨' => 220,
+ '︩' => 220,
+ '︪' => 220,
+ '︫' => 220,
+ '︬' => 220,
+ '︭' => 220,
+ '︮' => 230,
+ '︯' => 230,
+ '𐇽' => 220,
+ '𐋠' => 220,
+ '𐍶' => 230,
+ '𐍷' => 230,
+ '𐍸' => 230,
+ '𐍹' => 230,
+ '𐍺' => 230,
+ '𐨍' => 220,
+ '𐨏' => 230,
+ '𐨸' => 230,
+ '𐨹' => 1,
+ '𐨺' => 220,
+ '𐨿' => 9,
+ '𐫥' => 230,
+ '𐫦' => 220,
+ '𐴤' => 230,
+ '𐴥' => 230,
+ '𐴦' => 230,
+ '𐴧' => 230,
+ '𐺫' => 230,
+ '𐺬' => 230,
+ '𐽆' => 220,
+ '𐽇' => 220,
+ '𐽈' => 230,
+ '𐽉' => 230,
+ '𐽊' => 230,
+ '𐽋' => 220,
+ '𐽌' => 230,
+ '𐽍' => 220,
+ '𐽎' => 220,
+ '𐽏' => 220,
+ '𐽐' => 220,
+ '𑁆' => 9,
+ '𑁿' => 9,
+ '𑂹' => 9,
+ '𑂺' => 7,
+ '𑄀' => 230,
+ '𑄁' => 230,
+ '𑄂' => 230,
+ '𑄳' => 9,
+ '𑄴' => 9,
+ '𑅳' => 7,
+ '𑇀' => 9,
+ '𑇊' => 7,
+ '𑈵' => 9,
+ '𑈶' => 7,
+ '𑋩' => 7,
+ '𑋪' => 9,
+ '𑌻' => 7,
+ '𑌼' => 7,
+ '𑍍' => 9,
+ '𑍦' => 230,
+ '𑍧' => 230,
+ '𑍨' => 230,
+ '𑍩' => 230,
+ '𑍪' => 230,
+ '𑍫' => 230,
+ '𑍬' => 230,
+ '𑍰' => 230,
+ '𑍱' => 230,
+ '𑍲' => 230,
+ '𑍳' => 230,
+ '𑍴' => 230,
+ '𑑂' => 9,
+ '𑑆' => 7,
+ '𑑞' => 230,
+ '𑓂' => 9,
+ '𑓃' => 7,
+ '𑖿' => 9,
+ '𑗀' => 7,
+ '𑘿' => 9,
+ '𑚶' => 9,
+ '𑚷' => 7,
+ '𑜫' => 9,
+ '𑠹' => 9,
+ '𑠺' => 7,
+ '𑤽' => 9,
+ '𑤾' => 9,
+ '𑥃' => 7,
+ '𑧠' => 9,
+ '𑨴' => 9,
+ '𑩇' => 9,
+ '𑪙' => 9,
+ '𑰿' => 9,
+ '𑵂' => 7,
+ '𑵄' => 9,
+ '𑵅' => 9,
+ '𑶗' => 9,
+ '𖫰' => 1,
+ '𖫱' => 1,
+ '𖫲' => 1,
+ '𖫳' => 1,
+ '𖫴' => 1,
+ '𖬰' => 230,
+ '𖬱' => 230,
+ '𖬲' => 230,
+ '𖬳' => 230,
+ '𖬴' => 230,
+ '𖬵' => 230,
+ '𖬶' => 230,
+ '𖿰' => 6,
+ '𖿱' => 6,
+ '𛲞' => 1,
+ '𝅥' => 216,
+ '𝅦' => 216,
+ '𝅧' => 1,
+ '𝅨' => 1,
+ '𝅩' => 1,
+ '𝅭' => 226,
+ '𝅮' => 216,
+ '𝅯' => 216,
+ '𝅰' => 216,
+ '𝅱' => 216,
+ '𝅲' => 216,
+ '𝅻' => 220,
+ '𝅼' => 220,
+ '𝅽' => 220,
+ '𝅾' => 220,
+ '𝅿' => 220,
+ '𝆀' => 220,
+ '𝆁' => 220,
+ '𝆂' => 220,
+ '𝆅' => 230,
+ '𝆆' => 230,
+ '𝆇' => 230,
+ '𝆈' => 230,
+ '𝆉' => 230,
+ '𝆊' => 220,
+ '𝆋' => 220,
+ '𝆪' => 230,
+ '𝆫' => 230,
+ '𝆬' => 230,
+ '𝆭' => 230,
+ '𝉂' => 230,
+ '𝉃' => 230,
+ '𝉄' => 230,
+ '𞀀' => 230,
+ '𞀁' => 230,
+ '𞀂' => 230,
+ '𞀃' => 230,
+ '𞀄' => 230,
+ '𞀅' => 230,
+ '𞀆' => 230,
+ '𞀈' => 230,
+ '𞀉' => 230,
+ '𞀊' => 230,
+ '𞀋' => 230,
+ '𞀌' => 230,
+ '𞀍' => 230,
+ '𞀎' => 230,
+ '𞀏' => 230,
+ '𞀐' => 230,
+ '𞀑' => 230,
+ '𞀒' => 230,
+ '𞀓' => 230,
+ '𞀔' => 230,
+ '𞀕' => 230,
+ '𞀖' => 230,
+ '𞀗' => 230,
+ '𞀘' => 230,
+ '𞀛' => 230,
+ '𞀜' => 230,
+ '𞀝' => 230,
+ '𞀞' => 230,
+ '𞀟' => 230,
+ '𞀠' => 230,
+ '𞀡' => 230,
+ '𞀣' => 230,
+ '𞀤' => 230,
+ '𞀦' => 230,
+ '𞀧' => 230,
+ '𞀨' => 230,
+ '𞀩' => 230,
+ '𞀪' => 230,
+ '𞄰' => 230,
+ '𞄱' => 230,
+ '𞄲' => 230,
+ '𞄳' => 230,
+ '𞄴' => 230,
+ '𞄵' => 230,
+ '𞄶' => 230,
+ '𞋬' => 230,
+ '𞋭' => 230,
+ '𞋮' => 230,
+ '𞋯' => 230,
+ '𞣐' => 220,
+ '𞣑' => 220,
+ '𞣒' => 220,
+ '𞣓' => 220,
+ '𞣔' => 220,
+ '𞣕' => 220,
+ '𞣖' => 220,
+ '𞥄' => 230,
+ '𞥅' => 230,
+ '𞥆' => 230,
+ '𞥇' => 230,
+ '𞥈' => 230,
+ '𞥉' => 230,
+ '𞥊' => 7,
+);
diff --git a/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php b/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php
new file mode 100644
index 000000000..157490289
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php
@@ -0,0 +1,3695 @@
+ ' ',
+ '¨' => ' ̈',
+ 'ª' => 'a',
+ '¯' => ' ̄',
+ '²' => '2',
+ '³' => '3',
+ '´' => ' ́',
+ 'µ' => 'μ',
+ '¸' => ' ̧',
+ '¹' => '1',
+ 'º' => 'o',
+ '¼' => '1⁄4',
+ '½' => '1⁄2',
+ '¾' => '3⁄4',
+ 'IJ' => 'IJ',
+ 'ij' => 'ij',
+ 'Ŀ' => 'L·',
+ 'ŀ' => 'l·',
+ 'ʼn' => 'ʼn',
+ 'ſ' => 's',
+ 'DŽ' => 'DŽ',
+ 'Dž' => 'Dž',
+ 'dž' => 'dž',
+ 'LJ' => 'LJ',
+ 'Lj' => 'Lj',
+ 'lj' => 'lj',
+ 'NJ' => 'NJ',
+ 'Nj' => 'Nj',
+ 'nj' => 'nj',
+ 'DZ' => 'DZ',
+ 'Dz' => 'Dz',
+ 'dz' => 'dz',
+ 'ʰ' => 'h',
+ 'ʱ' => 'ɦ',
+ 'ʲ' => 'j',
+ 'ʳ' => 'r',
+ 'ʴ' => 'ɹ',
+ 'ʵ' => 'ɻ',
+ 'ʶ' => 'ʁ',
+ 'ʷ' => 'w',
+ 'ʸ' => 'y',
+ '˘' => ' ̆',
+ '˙' => ' ̇',
+ '˚' => ' ̊',
+ '˛' => ' ̨',
+ '˜' => ' ̃',
+ '˝' => ' ̋',
+ 'ˠ' => 'ɣ',
+ 'ˡ' => 'l',
+ 'ˢ' => 's',
+ 'ˣ' => 'x',
+ 'ˤ' => 'ʕ',
+ 'ͺ' => ' ͅ',
+ '΄' => ' ́',
+ '΅' => ' ̈́',
+ 'ϐ' => 'β',
+ 'ϑ' => 'θ',
+ 'ϒ' => 'Υ',
+ 'ϓ' => 'Ύ',
+ 'ϔ' => 'Ϋ',
+ 'ϕ' => 'φ',
+ 'ϖ' => 'π',
+ 'ϰ' => 'κ',
+ 'ϱ' => 'ρ',
+ 'ϲ' => 'ς',
+ 'ϴ' => 'Θ',
+ 'ϵ' => 'ε',
+ 'Ϲ' => 'Σ',
+ 'և' => 'եւ',
+ 'ٵ' => 'اٴ',
+ 'ٶ' => 'وٴ',
+ 'ٷ' => 'ۇٴ',
+ 'ٸ' => 'يٴ',
+ 'ำ' => 'ํา',
+ 'ຳ' => 'ໍາ',
+ 'ໜ' => 'ຫນ',
+ 'ໝ' => 'ຫມ',
+ '༌' => '་',
+ 'ཷ' => 'ྲཱྀ',
+ 'ཹ' => 'ླཱྀ',
+ 'ჼ' => 'ნ',
+ 'ᴬ' => 'A',
+ 'ᴭ' => 'Æ',
+ 'ᴮ' => 'B',
+ 'ᴰ' => 'D',
+ 'ᴱ' => 'E',
+ 'ᴲ' => 'Ǝ',
+ 'ᴳ' => 'G',
+ 'ᴴ' => 'H',
+ 'ᴵ' => 'I',
+ 'ᴶ' => 'J',
+ 'ᴷ' => 'K',
+ 'ᴸ' => 'L',
+ 'ᴹ' => 'M',
+ 'ᴺ' => 'N',
+ 'ᴼ' => 'O',
+ 'ᴽ' => 'Ȣ',
+ 'ᴾ' => 'P',
+ 'ᴿ' => 'R',
+ 'ᵀ' => 'T',
+ 'ᵁ' => 'U',
+ 'ᵂ' => 'W',
+ 'ᵃ' => 'a',
+ 'ᵄ' => 'ɐ',
+ 'ᵅ' => 'ɑ',
+ 'ᵆ' => 'ᴂ',
+ 'ᵇ' => 'b',
+ 'ᵈ' => 'd',
+ 'ᵉ' => 'e',
+ 'ᵊ' => 'ə',
+ 'ᵋ' => 'ɛ',
+ 'ᵌ' => 'ɜ',
+ 'ᵍ' => 'g',
+ 'ᵏ' => 'k',
+ 'ᵐ' => 'm',
+ 'ᵑ' => 'ŋ',
+ 'ᵒ' => 'o',
+ 'ᵓ' => 'ɔ',
+ 'ᵔ' => 'ᴖ',
+ 'ᵕ' => 'ᴗ',
+ 'ᵖ' => 'p',
+ 'ᵗ' => 't',
+ 'ᵘ' => 'u',
+ 'ᵙ' => 'ᴝ',
+ 'ᵚ' => 'ɯ',
+ 'ᵛ' => 'v',
+ 'ᵜ' => 'ᴥ',
+ 'ᵝ' => 'β',
+ 'ᵞ' => 'γ',
+ 'ᵟ' => 'δ',
+ 'ᵠ' => 'φ',
+ 'ᵡ' => 'χ',
+ 'ᵢ' => 'i',
+ 'ᵣ' => 'r',
+ 'ᵤ' => 'u',
+ 'ᵥ' => 'v',
+ 'ᵦ' => 'β',
+ 'ᵧ' => 'γ',
+ 'ᵨ' => 'ρ',
+ 'ᵩ' => 'φ',
+ 'ᵪ' => 'χ',
+ 'ᵸ' => 'н',
+ 'ᶛ' => 'ɒ',
+ 'ᶜ' => 'c',
+ 'ᶝ' => 'ɕ',
+ 'ᶞ' => 'ð',
+ 'ᶟ' => 'ɜ',
+ 'ᶠ' => 'f',
+ 'ᶡ' => 'ɟ',
+ 'ᶢ' => 'ɡ',
+ 'ᶣ' => 'ɥ',
+ 'ᶤ' => 'ɨ',
+ 'ᶥ' => 'ɩ',
+ 'ᶦ' => 'ɪ',
+ 'ᶧ' => 'ᵻ',
+ 'ᶨ' => 'ʝ',
+ 'ᶩ' => 'ɭ',
+ 'ᶪ' => 'ᶅ',
+ 'ᶫ' => 'ʟ',
+ 'ᶬ' => 'ɱ',
+ 'ᶭ' => 'ɰ',
+ 'ᶮ' => 'ɲ',
+ 'ᶯ' => 'ɳ',
+ 'ᶰ' => 'ɴ',
+ 'ᶱ' => 'ɵ',
+ 'ᶲ' => 'ɸ',
+ 'ᶳ' => 'ʂ',
+ 'ᶴ' => 'ʃ',
+ 'ᶵ' => 'ƫ',
+ 'ᶶ' => 'ʉ',
+ 'ᶷ' => 'ʊ',
+ 'ᶸ' => 'ᴜ',
+ 'ᶹ' => 'ʋ',
+ 'ᶺ' => 'ʌ',
+ 'ᶻ' => 'z',
+ 'ᶼ' => 'ʐ',
+ 'ᶽ' => 'ʑ',
+ 'ᶾ' => 'ʒ',
+ 'ᶿ' => 'θ',
+ 'ẚ' => 'aʾ',
+ 'ẛ' => 'ṡ',
+ '᾽' => ' ̓',
+ '᾿' => ' ̓',
+ '῀' => ' ͂',
+ '῁' => ' ̈͂',
+ '῍' => ' ̓̀',
+ '῎' => ' ̓́',
+ '῏' => ' ̓͂',
+ '῝' => ' ̔̀',
+ '῞' => ' ̔́',
+ '῟' => ' ̔͂',
+ '῭' => ' ̈̀',
+ '΅' => ' ̈́',
+ '´' => ' ́',
+ '῾' => ' ̔',
+ ' ' => ' ',
+ ' ' => ' ',
+ ' ' => ' ',
+ ' ' => ' ',
+ ' ' => ' ',
+ ' ' => ' ',
+ ' ' => ' ',
+ ' ' => ' ',
+ ' ' => ' ',
+ ' ' => ' ',
+ ' ' => ' ',
+ '‑' => '‐',
+ '‗' => ' ̳',
+ '․' => '.',
+ '‥' => '..',
+ '…' => '...',
+ ' ' => ' ',
+ '″' => '′′',
+ '‴' => '′′′',
+ '‶' => '‵‵',
+ '‷' => '‵‵‵',
+ '‼' => '!!',
+ '‾' => ' ̅',
+ '⁇' => '??',
+ '⁈' => '?!',
+ '⁉' => '!?',
+ '⁗' => '′′′′',
+ ' ' => ' ',
+ '⁰' => '0',
+ 'ⁱ' => 'i',
+ '⁴' => '4',
+ '⁵' => '5',
+ '⁶' => '6',
+ '⁷' => '7',
+ '⁸' => '8',
+ '⁹' => '9',
+ '⁺' => '+',
+ '⁻' => '−',
+ '⁼' => '=',
+ '⁽' => '(',
+ '⁾' => ')',
+ 'ⁿ' => 'n',
+ '₀' => '0',
+ '₁' => '1',
+ '₂' => '2',
+ '₃' => '3',
+ '₄' => '4',
+ '₅' => '5',
+ '₆' => '6',
+ '₇' => '7',
+ '₈' => '8',
+ '₉' => '9',
+ '₊' => '+',
+ '₋' => '−',
+ '₌' => '=',
+ '₍' => '(',
+ '₎' => ')',
+ 'ₐ' => 'a',
+ 'ₑ' => 'e',
+ 'ₒ' => 'o',
+ 'ₓ' => 'x',
+ 'ₔ' => 'ə',
+ 'ₕ' => 'h',
+ 'ₖ' => 'k',
+ 'ₗ' => 'l',
+ 'ₘ' => 'm',
+ 'ₙ' => 'n',
+ 'ₚ' => 'p',
+ 'ₛ' => 's',
+ 'ₜ' => 't',
+ '₨' => 'Rs',
+ '℀' => 'a/c',
+ '℁' => 'a/s',
+ 'ℂ' => 'C',
+ '℃' => '°C',
+ '℅' => 'c/o',
+ '℆' => 'c/u',
+ 'ℇ' => 'Ɛ',
+ '℉' => '°F',
+ 'ℊ' => 'g',
+ 'ℋ' => 'H',
+ 'ℌ' => 'H',
+ 'ℍ' => 'H',
+ 'ℎ' => 'h',
+ 'ℏ' => 'ħ',
+ 'ℐ' => 'I',
+ 'ℑ' => 'I',
+ 'ℒ' => 'L',
+ 'ℓ' => 'l',
+ 'ℕ' => 'N',
+ '№' => 'No',
+ 'ℙ' => 'P',
+ 'ℚ' => 'Q',
+ 'ℛ' => 'R',
+ 'ℜ' => 'R',
+ 'ℝ' => 'R',
+ '℠' => 'SM',
+ '℡' => 'TEL',
+ '™' => 'TM',
+ 'ℤ' => 'Z',
+ 'ℨ' => 'Z',
+ 'ℬ' => 'B',
+ 'ℭ' => 'C',
+ 'ℯ' => 'e',
+ 'ℰ' => 'E',
+ 'ℱ' => 'F',
+ 'ℳ' => 'M',
+ 'ℴ' => 'o',
+ 'ℵ' => 'א',
+ 'ℶ' => 'ב',
+ 'ℷ' => 'ג',
+ 'ℸ' => 'ד',
+ 'ℹ' => 'i',
+ '℻' => 'FAX',
+ 'ℼ' => 'π',
+ 'ℽ' => 'γ',
+ 'ℾ' => 'Γ',
+ 'ℿ' => 'Π',
+ '⅀' => '∑',
+ 'ⅅ' => 'D',
+ 'ⅆ' => 'd',
+ 'ⅇ' => 'e',
+ 'ⅈ' => 'i',
+ 'ⅉ' => 'j',
+ '⅐' => '1⁄7',
+ '⅑' => '1⁄9',
+ '⅒' => '1⁄10',
+ '⅓' => '1⁄3',
+ '⅔' => '2⁄3',
+ '⅕' => '1⁄5',
+ '⅖' => '2⁄5',
+ '⅗' => '3⁄5',
+ '⅘' => '4⁄5',
+ '⅙' => '1⁄6',
+ '⅚' => '5⁄6',
+ '⅛' => '1⁄8',
+ '⅜' => '3⁄8',
+ '⅝' => '5⁄8',
+ '⅞' => '7⁄8',
+ '⅟' => '1⁄',
+ 'Ⅰ' => 'I',
+ 'Ⅱ' => 'II',
+ 'Ⅲ' => 'III',
+ 'Ⅳ' => 'IV',
+ 'Ⅴ' => 'V',
+ 'Ⅵ' => 'VI',
+ 'Ⅶ' => 'VII',
+ 'Ⅷ' => 'VIII',
+ 'Ⅸ' => 'IX',
+ 'Ⅹ' => 'X',
+ 'Ⅺ' => 'XI',
+ 'Ⅻ' => 'XII',
+ 'Ⅼ' => 'L',
+ 'Ⅽ' => 'C',
+ 'Ⅾ' => 'D',
+ 'Ⅿ' => 'M',
+ 'ⅰ' => 'i',
+ 'ⅱ' => 'ii',
+ 'ⅲ' => 'iii',
+ 'ⅳ' => 'iv',
+ 'ⅴ' => 'v',
+ 'ⅵ' => 'vi',
+ 'ⅶ' => 'vii',
+ 'ⅷ' => 'viii',
+ 'ⅸ' => 'ix',
+ 'ⅹ' => 'x',
+ 'ⅺ' => 'xi',
+ 'ⅻ' => 'xii',
+ 'ⅼ' => 'l',
+ 'ⅽ' => 'c',
+ 'ⅾ' => 'd',
+ 'ⅿ' => 'm',
+ '↉' => '0⁄3',
+ '∬' => '∫∫',
+ '∭' => '∫∫∫',
+ '∯' => '∮∮',
+ '∰' => '∮∮∮',
+ '①' => '1',
+ '②' => '2',
+ '③' => '3',
+ '④' => '4',
+ '⑤' => '5',
+ '⑥' => '6',
+ '⑦' => '7',
+ '⑧' => '8',
+ '⑨' => '9',
+ '⑩' => '10',
+ '⑪' => '11',
+ '⑫' => '12',
+ '⑬' => '13',
+ '⑭' => '14',
+ '⑮' => '15',
+ '⑯' => '16',
+ '⑰' => '17',
+ '⑱' => '18',
+ '⑲' => '19',
+ '⑳' => '20',
+ '⑴' => '(1)',
+ '⑵' => '(2)',
+ '⑶' => '(3)',
+ '⑷' => '(4)',
+ '⑸' => '(5)',
+ '⑹' => '(6)',
+ '⑺' => '(7)',
+ '⑻' => '(8)',
+ '⑼' => '(9)',
+ '⑽' => '(10)',
+ '⑾' => '(11)',
+ '⑿' => '(12)',
+ '⒀' => '(13)',
+ '⒁' => '(14)',
+ '⒂' => '(15)',
+ '⒃' => '(16)',
+ '⒄' => '(17)',
+ '⒅' => '(18)',
+ '⒆' => '(19)',
+ '⒇' => '(20)',
+ '⒈' => '1.',
+ '⒉' => '2.',
+ '⒊' => '3.',
+ '⒋' => '4.',
+ '⒌' => '5.',
+ '⒍' => '6.',
+ '⒎' => '7.',
+ '⒏' => '8.',
+ '⒐' => '9.',
+ '⒑' => '10.',
+ '⒒' => '11.',
+ '⒓' => '12.',
+ '⒔' => '13.',
+ '⒕' => '14.',
+ '⒖' => '15.',
+ '⒗' => '16.',
+ '⒘' => '17.',
+ '⒙' => '18.',
+ '⒚' => '19.',
+ '⒛' => '20.',
+ '⒜' => '(a)',
+ '⒝' => '(b)',
+ '⒞' => '(c)',
+ '⒟' => '(d)',
+ '⒠' => '(e)',
+ '⒡' => '(f)',
+ '⒢' => '(g)',
+ '⒣' => '(h)',
+ '⒤' => '(i)',
+ '⒥' => '(j)',
+ '⒦' => '(k)',
+ '⒧' => '(l)',
+ '⒨' => '(m)',
+ '⒩' => '(n)',
+ '⒪' => '(o)',
+ '⒫' => '(p)',
+ '⒬' => '(q)',
+ '⒭' => '(r)',
+ '⒮' => '(s)',
+ '⒯' => '(t)',
+ '⒰' => '(u)',
+ '⒱' => '(v)',
+ '⒲' => '(w)',
+ '⒳' => '(x)',
+ '⒴' => '(y)',
+ '⒵' => '(z)',
+ 'Ⓐ' => 'A',
+ 'Ⓑ' => 'B',
+ 'Ⓒ' => 'C',
+ 'Ⓓ' => 'D',
+ 'Ⓔ' => 'E',
+ 'Ⓕ' => 'F',
+ 'Ⓖ' => 'G',
+ 'Ⓗ' => 'H',
+ 'Ⓘ' => 'I',
+ 'Ⓙ' => 'J',
+ 'Ⓚ' => 'K',
+ 'Ⓛ' => 'L',
+ 'Ⓜ' => 'M',
+ 'Ⓝ' => 'N',
+ 'Ⓞ' => 'O',
+ 'Ⓟ' => 'P',
+ 'Ⓠ' => 'Q',
+ 'Ⓡ' => 'R',
+ 'Ⓢ' => 'S',
+ 'Ⓣ' => 'T',
+ 'Ⓤ' => 'U',
+ 'Ⓥ' => 'V',
+ 'Ⓦ' => 'W',
+ 'Ⓧ' => 'X',
+ 'Ⓨ' => 'Y',
+ 'Ⓩ' => 'Z',
+ 'ⓐ' => 'a',
+ 'ⓑ' => 'b',
+ 'ⓒ' => 'c',
+ 'ⓓ' => 'd',
+ 'ⓔ' => 'e',
+ 'ⓕ' => 'f',
+ 'ⓖ' => 'g',
+ 'ⓗ' => 'h',
+ 'ⓘ' => 'i',
+ 'ⓙ' => 'j',
+ 'ⓚ' => 'k',
+ 'ⓛ' => 'l',
+ 'ⓜ' => 'm',
+ 'ⓝ' => 'n',
+ 'ⓞ' => 'o',
+ 'ⓟ' => 'p',
+ 'ⓠ' => 'q',
+ 'ⓡ' => 'r',
+ 'ⓢ' => 's',
+ 'ⓣ' => 't',
+ 'ⓤ' => 'u',
+ 'ⓥ' => 'v',
+ 'ⓦ' => 'w',
+ 'ⓧ' => 'x',
+ 'ⓨ' => 'y',
+ 'ⓩ' => 'z',
+ '⓪' => '0',
+ '⨌' => '∫∫∫∫',
+ '⩴' => '::=',
+ '⩵' => '==',
+ '⩶' => '===',
+ 'ⱼ' => 'j',
+ 'ⱽ' => 'V',
+ 'ⵯ' => 'ⵡ',
+ '⺟' => '母',
+ '⻳' => '龟',
+ '⼀' => '一',
+ '⼁' => '丨',
+ '⼂' => '丶',
+ '⼃' => '丿',
+ '⼄' => '乙',
+ '⼅' => '亅',
+ '⼆' => '二',
+ '⼇' => '亠',
+ '⼈' => '人',
+ '⼉' => '儿',
+ '⼊' => '入',
+ '⼋' => '八',
+ '⼌' => '冂',
+ '⼍' => '冖',
+ '⼎' => '冫',
+ '⼏' => '几',
+ '⼐' => '凵',
+ '⼑' => '刀',
+ '⼒' => '力',
+ '⼓' => '勹',
+ '⼔' => '匕',
+ '⼕' => '匚',
+ '⼖' => '匸',
+ '⼗' => '十',
+ '⼘' => '卜',
+ '⼙' => '卩',
+ '⼚' => '厂',
+ '⼛' => '厶',
+ '⼜' => '又',
+ '⼝' => '口',
+ '⼞' => '囗',
+ '⼟' => '土',
+ '⼠' => '士',
+ '⼡' => '夂',
+ '⼢' => '夊',
+ '⼣' => '夕',
+ '⼤' => '大',
+ '⼥' => '女',
+ '⼦' => '子',
+ '⼧' => '宀',
+ '⼨' => '寸',
+ '⼩' => '小',
+ '⼪' => '尢',
+ '⼫' => '尸',
+ '⼬' => '屮',
+ '⼭' => '山',
+ '⼮' => '巛',
+ '⼯' => '工',
+ '⼰' => '己',
+ '⼱' => '巾',
+ '⼲' => '干',
+ '⼳' => '幺',
+ '⼴' => '广',
+ '⼵' => '廴',
+ '⼶' => '廾',
+ '⼷' => '弋',
+ '⼸' => '弓',
+ '⼹' => '彐',
+ '⼺' => '彡',
+ '⼻' => '彳',
+ '⼼' => '心',
+ '⼽' => '戈',
+ '⼾' => '戶',
+ '⼿' => '手',
+ '⽀' => '支',
+ '⽁' => '攴',
+ '⽂' => '文',
+ '⽃' => '斗',
+ '⽄' => '斤',
+ '⽅' => '方',
+ '⽆' => '无',
+ '⽇' => '日',
+ '⽈' => '曰',
+ '⽉' => '月',
+ '⽊' => '木',
+ '⽋' => '欠',
+ '⽌' => '止',
+ '⽍' => '歹',
+ '⽎' => '殳',
+ '⽏' => '毋',
+ '⽐' => '比',
+ '⽑' => '毛',
+ '⽒' => '氏',
+ '⽓' => '气',
+ '⽔' => '水',
+ '⽕' => '火',
+ '⽖' => '爪',
+ '⽗' => '父',
+ '⽘' => '爻',
+ '⽙' => '爿',
+ '⽚' => '片',
+ '⽛' => '牙',
+ '⽜' => '牛',
+ '⽝' => '犬',
+ '⽞' => '玄',
+ '⽟' => '玉',
+ '⽠' => '瓜',
+ '⽡' => '瓦',
+ '⽢' => '甘',
+ '⽣' => '生',
+ '⽤' => '用',
+ '⽥' => '田',
+ '⽦' => '疋',
+ '⽧' => '疒',
+ '⽨' => '癶',
+ '⽩' => '白',
+ '⽪' => '皮',
+ '⽫' => '皿',
+ '⽬' => '目',
+ '⽭' => '矛',
+ '⽮' => '矢',
+ '⽯' => '石',
+ '⽰' => '示',
+ '⽱' => '禸',
+ '⽲' => '禾',
+ '⽳' => '穴',
+ '⽴' => '立',
+ '⽵' => '竹',
+ '⽶' => '米',
+ '⽷' => '糸',
+ '⽸' => '缶',
+ '⽹' => '网',
+ '⽺' => '羊',
+ '⽻' => '羽',
+ '⽼' => '老',
+ '⽽' => '而',
+ '⽾' => '耒',
+ '⽿' => '耳',
+ '⾀' => '聿',
+ '⾁' => '肉',
+ '⾂' => '臣',
+ '⾃' => '自',
+ '⾄' => '至',
+ '⾅' => '臼',
+ '⾆' => '舌',
+ '⾇' => '舛',
+ '⾈' => '舟',
+ '⾉' => '艮',
+ '⾊' => '色',
+ '⾋' => '艸',
+ '⾌' => '虍',
+ '⾍' => '虫',
+ '⾎' => '血',
+ '⾏' => '行',
+ '⾐' => '衣',
+ '⾑' => '襾',
+ '⾒' => '見',
+ '⾓' => '角',
+ '⾔' => '言',
+ '⾕' => '谷',
+ '⾖' => '豆',
+ '⾗' => '豕',
+ '⾘' => '豸',
+ '⾙' => '貝',
+ '⾚' => '赤',
+ '⾛' => '走',
+ '⾜' => '足',
+ '⾝' => '身',
+ '⾞' => '車',
+ '⾟' => '辛',
+ '⾠' => '辰',
+ '⾡' => '辵',
+ '⾢' => '邑',
+ '⾣' => '酉',
+ '⾤' => '釆',
+ '⾥' => '里',
+ '⾦' => '金',
+ '⾧' => '長',
+ '⾨' => '門',
+ '⾩' => '阜',
+ '⾪' => '隶',
+ '⾫' => '隹',
+ '⾬' => '雨',
+ '⾭' => '靑',
+ '⾮' => '非',
+ '⾯' => '面',
+ '⾰' => '革',
+ '⾱' => '韋',
+ '⾲' => '韭',
+ '⾳' => '音',
+ '⾴' => '頁',
+ '⾵' => '風',
+ '⾶' => '飛',
+ '⾷' => '食',
+ '⾸' => '首',
+ '⾹' => '香',
+ '⾺' => '馬',
+ '⾻' => '骨',
+ '⾼' => '高',
+ '⾽' => '髟',
+ '⾾' => '鬥',
+ '⾿' => '鬯',
+ '⿀' => '鬲',
+ '⿁' => '鬼',
+ '⿂' => '魚',
+ '⿃' => '鳥',
+ '⿄' => '鹵',
+ '⿅' => '鹿',
+ '⿆' => '麥',
+ '⿇' => '麻',
+ '⿈' => '黃',
+ '⿉' => '黍',
+ '⿊' => '黑',
+ '⿋' => '黹',
+ '⿌' => '黽',
+ '⿍' => '鼎',
+ '⿎' => '鼓',
+ '⿏' => '鼠',
+ '⿐' => '鼻',
+ '⿑' => '齊',
+ '⿒' => '齒',
+ '⿓' => '龍',
+ '⿔' => '龜',
+ '⿕' => '龠',
+ ' ' => ' ',
+ '〶' => '〒',
+ '〸' => '十',
+ '〹' => '卄',
+ '〺' => '卅',
+ '゛' => ' ゙',
+ '゜' => ' ゚',
+ 'ゟ' => 'より',
+ 'ヿ' => 'コト',
+ 'ㄱ' => 'ᄀ',
+ 'ㄲ' => 'ᄁ',
+ 'ㄳ' => 'ᆪ',
+ 'ㄴ' => 'ᄂ',
+ 'ㄵ' => 'ᆬ',
+ 'ㄶ' => 'ᆭ',
+ 'ㄷ' => 'ᄃ',
+ 'ㄸ' => 'ᄄ',
+ 'ㄹ' => 'ᄅ',
+ 'ㄺ' => 'ᆰ',
+ 'ㄻ' => 'ᆱ',
+ 'ㄼ' => 'ᆲ',
+ 'ㄽ' => 'ᆳ',
+ 'ㄾ' => 'ᆴ',
+ 'ㄿ' => 'ᆵ',
+ 'ㅀ' => 'ᄚ',
+ 'ㅁ' => 'ᄆ',
+ 'ㅂ' => 'ᄇ',
+ 'ㅃ' => 'ᄈ',
+ 'ㅄ' => 'ᄡ',
+ 'ㅅ' => 'ᄉ',
+ 'ㅆ' => 'ᄊ',
+ 'ㅇ' => 'ᄋ',
+ 'ㅈ' => 'ᄌ',
+ 'ㅉ' => 'ᄍ',
+ 'ㅊ' => 'ᄎ',
+ 'ㅋ' => 'ᄏ',
+ 'ㅌ' => 'ᄐ',
+ 'ㅍ' => 'ᄑ',
+ 'ㅎ' => 'ᄒ',
+ 'ㅏ' => 'ᅡ',
+ 'ㅐ' => 'ᅢ',
+ 'ㅑ' => 'ᅣ',
+ 'ㅒ' => 'ᅤ',
+ 'ㅓ' => 'ᅥ',
+ 'ㅔ' => 'ᅦ',
+ 'ㅕ' => 'ᅧ',
+ 'ㅖ' => 'ᅨ',
+ 'ㅗ' => 'ᅩ',
+ 'ㅘ' => 'ᅪ',
+ 'ㅙ' => 'ᅫ',
+ 'ㅚ' => 'ᅬ',
+ 'ㅛ' => 'ᅭ',
+ 'ㅜ' => 'ᅮ',
+ 'ㅝ' => 'ᅯ',
+ 'ㅞ' => 'ᅰ',
+ 'ㅟ' => 'ᅱ',
+ 'ㅠ' => 'ᅲ',
+ 'ㅡ' => 'ᅳ',
+ 'ㅢ' => 'ᅴ',
+ 'ㅣ' => 'ᅵ',
+ 'ㅤ' => 'ᅠ',
+ 'ㅥ' => 'ᄔ',
+ 'ㅦ' => 'ᄕ',
+ 'ㅧ' => 'ᇇ',
+ 'ㅨ' => 'ᇈ',
+ 'ㅩ' => 'ᇌ',
+ 'ㅪ' => 'ᇎ',
+ 'ㅫ' => 'ᇓ',
+ 'ㅬ' => 'ᇗ',
+ 'ㅭ' => 'ᇙ',
+ 'ㅮ' => 'ᄜ',
+ 'ㅯ' => 'ᇝ',
+ 'ㅰ' => 'ᇟ',
+ 'ㅱ' => 'ᄝ',
+ 'ㅲ' => 'ᄞ',
+ 'ㅳ' => 'ᄠ',
+ 'ㅴ' => 'ᄢ',
+ 'ㅵ' => 'ᄣ',
+ 'ㅶ' => 'ᄧ',
+ 'ㅷ' => 'ᄩ',
+ 'ㅸ' => 'ᄫ',
+ 'ㅹ' => 'ᄬ',
+ 'ㅺ' => 'ᄭ',
+ 'ㅻ' => 'ᄮ',
+ 'ㅼ' => 'ᄯ',
+ 'ㅽ' => 'ᄲ',
+ 'ㅾ' => 'ᄶ',
+ 'ㅿ' => 'ᅀ',
+ 'ㆀ' => 'ᅇ',
+ 'ㆁ' => 'ᅌ',
+ 'ㆂ' => 'ᇱ',
+ 'ㆃ' => 'ᇲ',
+ 'ㆄ' => 'ᅗ',
+ 'ㆅ' => 'ᅘ',
+ 'ㆆ' => 'ᅙ',
+ 'ㆇ' => 'ᆄ',
+ 'ㆈ' => 'ᆅ',
+ 'ㆉ' => 'ᆈ',
+ 'ㆊ' => 'ᆑ',
+ 'ㆋ' => 'ᆒ',
+ 'ㆌ' => 'ᆔ',
+ 'ㆍ' => 'ᆞ',
+ 'ㆎ' => 'ᆡ',
+ '㆒' => '一',
+ '㆓' => '二',
+ '㆔' => '三',
+ '㆕' => '四',
+ '㆖' => '上',
+ '㆗' => '中',
+ '㆘' => '下',
+ '㆙' => '甲',
+ '㆚' => '乙',
+ '㆛' => '丙',
+ '㆜' => '丁',
+ '㆝' => '天',
+ '㆞' => '地',
+ '㆟' => '人',
+ '㈀' => '(ᄀ)',
+ '㈁' => '(ᄂ)',
+ '㈂' => '(ᄃ)',
+ '㈃' => '(ᄅ)',
+ '㈄' => '(ᄆ)',
+ '㈅' => '(ᄇ)',
+ '㈆' => '(ᄉ)',
+ '㈇' => '(ᄋ)',
+ '㈈' => '(ᄌ)',
+ '㈉' => '(ᄎ)',
+ '㈊' => '(ᄏ)',
+ '㈋' => '(ᄐ)',
+ '㈌' => '(ᄑ)',
+ '㈍' => '(ᄒ)',
+ '㈎' => '(가)',
+ '㈏' => '(나)',
+ '㈐' => '(다)',
+ '㈑' => '(라)',
+ '㈒' => '(마)',
+ '㈓' => '(바)',
+ '㈔' => '(사)',
+ '㈕' => '(아)',
+ '㈖' => '(자)',
+ '㈗' => '(차)',
+ '㈘' => '(카)',
+ '㈙' => '(타)',
+ '㈚' => '(파)',
+ '㈛' => '(하)',
+ '㈜' => '(주)',
+ '㈝' => '(오전)',
+ '㈞' => '(오후)',
+ '㈠' => '(一)',
+ '㈡' => '(二)',
+ '㈢' => '(三)',
+ '㈣' => '(四)',
+ '㈤' => '(五)',
+ '㈥' => '(六)',
+ '㈦' => '(七)',
+ '㈧' => '(八)',
+ '㈨' => '(九)',
+ '㈩' => '(十)',
+ '㈪' => '(月)',
+ '㈫' => '(火)',
+ '㈬' => '(水)',
+ '㈭' => '(木)',
+ '㈮' => '(金)',
+ '㈯' => '(土)',
+ '㈰' => '(日)',
+ '㈱' => '(株)',
+ '㈲' => '(有)',
+ '㈳' => '(社)',
+ '㈴' => '(名)',
+ '㈵' => '(特)',
+ '㈶' => '(財)',
+ '㈷' => '(祝)',
+ '㈸' => '(労)',
+ '㈹' => '(代)',
+ '㈺' => '(呼)',
+ '㈻' => '(学)',
+ '㈼' => '(監)',
+ '㈽' => '(企)',
+ '㈾' => '(資)',
+ '㈿' => '(協)',
+ '㉀' => '(祭)',
+ '㉁' => '(休)',
+ '㉂' => '(自)',
+ '㉃' => '(至)',
+ '㉄' => '問',
+ '㉅' => '幼',
+ '㉆' => '文',
+ '㉇' => '箏',
+ '㉐' => 'PTE',
+ '㉑' => '21',
+ '㉒' => '22',
+ '㉓' => '23',
+ '㉔' => '24',
+ '㉕' => '25',
+ '㉖' => '26',
+ '㉗' => '27',
+ '㉘' => '28',
+ '㉙' => '29',
+ '㉚' => '30',
+ '㉛' => '31',
+ '㉜' => '32',
+ '㉝' => '33',
+ '㉞' => '34',
+ '㉟' => '35',
+ '㉠' => 'ᄀ',
+ '㉡' => 'ᄂ',
+ '㉢' => 'ᄃ',
+ '㉣' => 'ᄅ',
+ '㉤' => 'ᄆ',
+ '㉥' => 'ᄇ',
+ '㉦' => 'ᄉ',
+ '㉧' => 'ᄋ',
+ '㉨' => 'ᄌ',
+ '㉩' => 'ᄎ',
+ '㉪' => 'ᄏ',
+ '㉫' => 'ᄐ',
+ '㉬' => 'ᄑ',
+ '㉭' => 'ᄒ',
+ '㉮' => '가',
+ '㉯' => '나',
+ '㉰' => '다',
+ '㉱' => '라',
+ '㉲' => '마',
+ '㉳' => '바',
+ '㉴' => '사',
+ '㉵' => '아',
+ '㉶' => '자',
+ '㉷' => '차',
+ '㉸' => '카',
+ '㉹' => '타',
+ '㉺' => '파',
+ '㉻' => '하',
+ '㉼' => '참고',
+ '㉽' => '주의',
+ '㉾' => '우',
+ '㊀' => '一',
+ '㊁' => '二',
+ '㊂' => '三',
+ '㊃' => '四',
+ '㊄' => '五',
+ '㊅' => '六',
+ '㊆' => '七',
+ '㊇' => '八',
+ '㊈' => '九',
+ '㊉' => '十',
+ '㊊' => '月',
+ '㊋' => '火',
+ '㊌' => '水',
+ '㊍' => '木',
+ '㊎' => '金',
+ '㊏' => '土',
+ '㊐' => '日',
+ '㊑' => '株',
+ '㊒' => '有',
+ '㊓' => '社',
+ '㊔' => '名',
+ '㊕' => '特',
+ '㊖' => '財',
+ '㊗' => '祝',
+ '㊘' => '労',
+ '㊙' => '秘',
+ '㊚' => '男',
+ '㊛' => '女',
+ '㊜' => '適',
+ '㊝' => '優',
+ '㊞' => '印',
+ '㊟' => '注',
+ '㊠' => '項',
+ '㊡' => '休',
+ '㊢' => '写',
+ '㊣' => '正',
+ '㊤' => '上',
+ '㊥' => '中',
+ '㊦' => '下',
+ '㊧' => '左',
+ '㊨' => '右',
+ '㊩' => '医',
+ '㊪' => '宗',
+ '㊫' => '学',
+ '㊬' => '監',
+ '㊭' => '企',
+ '㊮' => '資',
+ '㊯' => '協',
+ '㊰' => '夜',
+ '㊱' => '36',
+ '㊲' => '37',
+ '㊳' => '38',
+ '㊴' => '39',
+ '㊵' => '40',
+ '㊶' => '41',
+ '㊷' => '42',
+ '㊸' => '43',
+ '㊹' => '44',
+ '㊺' => '45',
+ '㊻' => '46',
+ '㊼' => '47',
+ '㊽' => '48',
+ '㊾' => '49',
+ '㊿' => '50',
+ '㋀' => '1月',
+ '㋁' => '2月',
+ '㋂' => '3月',
+ '㋃' => '4月',
+ '㋄' => '5月',
+ '㋅' => '6月',
+ '㋆' => '7月',
+ '㋇' => '8月',
+ '㋈' => '9月',
+ '㋉' => '10月',
+ '㋊' => '11月',
+ '㋋' => '12月',
+ '㋌' => 'Hg',
+ '㋍' => 'erg',
+ '㋎' => 'eV',
+ '㋏' => 'LTD',
+ '㋐' => 'ア',
+ '㋑' => 'イ',
+ '㋒' => 'ウ',
+ '㋓' => 'エ',
+ '㋔' => 'オ',
+ '㋕' => 'カ',
+ '㋖' => 'キ',
+ '㋗' => 'ク',
+ '㋘' => 'ケ',
+ '㋙' => 'コ',
+ '㋚' => 'サ',
+ '㋛' => 'シ',
+ '㋜' => 'ス',
+ '㋝' => 'セ',
+ '㋞' => 'ソ',
+ '㋟' => 'タ',
+ '㋠' => 'チ',
+ '㋡' => 'ツ',
+ '㋢' => 'テ',
+ '㋣' => 'ト',
+ '㋤' => 'ナ',
+ '㋥' => 'ニ',
+ '㋦' => 'ヌ',
+ '㋧' => 'ネ',
+ '㋨' => 'ノ',
+ '㋩' => 'ハ',
+ '㋪' => 'ヒ',
+ '㋫' => 'フ',
+ '㋬' => 'ヘ',
+ '㋭' => 'ホ',
+ '㋮' => 'マ',
+ '㋯' => 'ミ',
+ '㋰' => 'ム',
+ '㋱' => 'メ',
+ '㋲' => 'モ',
+ '㋳' => 'ヤ',
+ '㋴' => 'ユ',
+ '㋵' => 'ヨ',
+ '㋶' => 'ラ',
+ '㋷' => 'リ',
+ '㋸' => 'ル',
+ '㋹' => 'レ',
+ '㋺' => 'ロ',
+ '㋻' => 'ワ',
+ '㋼' => 'ヰ',
+ '㋽' => 'ヱ',
+ '㋾' => 'ヲ',
+ '㋿' => '令和',
+ '㌀' => 'アパート',
+ '㌁' => 'アルファ',
+ '㌂' => 'アンペア',
+ '㌃' => 'アール',
+ '㌄' => 'イニング',
+ '㌅' => 'インチ',
+ '㌆' => 'ウォン',
+ '㌇' => 'エスクード',
+ '㌈' => 'エーカー',
+ '㌉' => 'オンス',
+ '㌊' => 'オーム',
+ '㌋' => 'カイリ',
+ '㌌' => 'カラット',
+ '㌍' => 'カロリー',
+ '㌎' => 'ガロン',
+ '㌏' => 'ガンマ',
+ '㌐' => 'ギガ',
+ '㌑' => 'ギニー',
+ '㌒' => 'キュリー',
+ '㌓' => 'ギルダー',
+ '㌔' => 'キロ',
+ '㌕' => 'キログラム',
+ '㌖' => 'キロメートル',
+ '㌗' => 'キロワット',
+ '㌘' => 'グラム',
+ '㌙' => 'グラムトン',
+ '㌚' => 'クルゼイロ',
+ '㌛' => 'クローネ',
+ '㌜' => 'ケース',
+ '㌝' => 'コルナ',
+ '㌞' => 'コーポ',
+ '㌟' => 'サイクル',
+ '㌠' => 'サンチーム',
+ '㌡' => 'シリング',
+ '㌢' => 'センチ',
+ '㌣' => 'セント',
+ '㌤' => 'ダース',
+ '㌥' => 'デシ',
+ '㌦' => 'ドル',
+ '㌧' => 'トン',
+ '㌨' => 'ナノ',
+ '㌩' => 'ノット',
+ '㌪' => 'ハイツ',
+ '㌫' => 'パーセント',
+ '㌬' => 'パーツ',
+ '㌭' => 'バーレル',
+ '㌮' => 'ピアストル',
+ '㌯' => 'ピクル',
+ '㌰' => 'ピコ',
+ '㌱' => 'ビル',
+ '㌲' => 'ファラッド',
+ '㌳' => 'フィート',
+ '㌴' => 'ブッシェル',
+ '㌵' => 'フラン',
+ '㌶' => 'ヘクタール',
+ '㌷' => 'ペソ',
+ '㌸' => 'ペニヒ',
+ '㌹' => 'ヘルツ',
+ '㌺' => 'ペンス',
+ '㌻' => 'ページ',
+ '㌼' => 'ベータ',
+ '㌽' => 'ポイント',
+ '㌾' => 'ボルト',
+ '㌿' => 'ホン',
+ '㍀' => 'ポンド',
+ '㍁' => 'ホール',
+ '㍂' => 'ホーン',
+ '㍃' => 'マイクロ',
+ '㍄' => 'マイル',
+ '㍅' => 'マッハ',
+ '㍆' => 'マルク',
+ '㍇' => 'マンション',
+ '㍈' => 'ミクロン',
+ '㍉' => 'ミリ',
+ '㍊' => 'ミリバール',
+ '㍋' => 'メガ',
+ '㍌' => 'メガトン',
+ '㍍' => 'メートル',
+ '㍎' => 'ヤード',
+ '㍏' => 'ヤール',
+ '㍐' => 'ユアン',
+ '㍑' => 'リットル',
+ '㍒' => 'リラ',
+ '㍓' => 'ルピー',
+ '㍔' => 'ルーブル',
+ '㍕' => 'レム',
+ '㍖' => 'レントゲン',
+ '㍗' => 'ワット',
+ '㍘' => '0点',
+ '㍙' => '1点',
+ '㍚' => '2点',
+ '㍛' => '3点',
+ '㍜' => '4点',
+ '㍝' => '5点',
+ '㍞' => '6点',
+ '㍟' => '7点',
+ '㍠' => '8点',
+ '㍡' => '9点',
+ '㍢' => '10点',
+ '㍣' => '11点',
+ '㍤' => '12点',
+ '㍥' => '13点',
+ '㍦' => '14点',
+ '㍧' => '15点',
+ '㍨' => '16点',
+ '㍩' => '17点',
+ '㍪' => '18点',
+ '㍫' => '19点',
+ '㍬' => '20点',
+ '㍭' => '21点',
+ '㍮' => '22点',
+ '㍯' => '23点',
+ '㍰' => '24点',
+ '㍱' => 'hPa',
+ '㍲' => 'da',
+ '㍳' => 'AU',
+ '㍴' => 'bar',
+ '㍵' => 'oV',
+ '㍶' => 'pc',
+ '㍷' => 'dm',
+ '㍸' => 'dm2',
+ '㍹' => 'dm3',
+ '㍺' => 'IU',
+ '㍻' => '平成',
+ '㍼' => '昭和',
+ '㍽' => '大正',
+ '㍾' => '明治',
+ '㍿' => '株式会社',
+ '㎀' => 'pA',
+ '㎁' => 'nA',
+ '㎂' => 'μA',
+ '㎃' => 'mA',
+ '㎄' => 'kA',
+ '㎅' => 'KB',
+ '㎆' => 'MB',
+ '㎇' => 'GB',
+ '㎈' => 'cal',
+ '㎉' => 'kcal',
+ '㎊' => 'pF',
+ '㎋' => 'nF',
+ '㎌' => 'μF',
+ '㎍' => 'μg',
+ '㎎' => 'mg',
+ '㎏' => 'kg',
+ '㎐' => 'Hz',
+ '㎑' => 'kHz',
+ '㎒' => 'MHz',
+ '㎓' => 'GHz',
+ '㎔' => 'THz',
+ '㎕' => 'μl',
+ '㎖' => 'ml',
+ '㎗' => 'dl',
+ '㎘' => 'kl',
+ '㎙' => 'fm',
+ '㎚' => 'nm',
+ '㎛' => 'μm',
+ '㎜' => 'mm',
+ '㎝' => 'cm',
+ '㎞' => 'km',
+ '㎟' => 'mm2',
+ '㎠' => 'cm2',
+ '㎡' => 'm2',
+ '㎢' => 'km2',
+ '㎣' => 'mm3',
+ '㎤' => 'cm3',
+ '㎥' => 'm3',
+ '㎦' => 'km3',
+ '㎧' => 'm∕s',
+ '㎨' => 'm∕s2',
+ '㎩' => 'Pa',
+ '㎪' => 'kPa',
+ '㎫' => 'MPa',
+ '㎬' => 'GPa',
+ '㎭' => 'rad',
+ '㎮' => 'rad∕s',
+ '㎯' => 'rad∕s2',
+ '㎰' => 'ps',
+ '㎱' => 'ns',
+ '㎲' => 'μs',
+ '㎳' => 'ms',
+ '㎴' => 'pV',
+ '㎵' => 'nV',
+ '㎶' => 'μV',
+ '㎷' => 'mV',
+ '㎸' => 'kV',
+ '㎹' => 'MV',
+ '㎺' => 'pW',
+ '㎻' => 'nW',
+ '㎼' => 'μW',
+ '㎽' => 'mW',
+ '㎾' => 'kW',
+ '㎿' => 'MW',
+ '㏀' => 'kΩ',
+ '㏁' => 'MΩ',
+ '㏂' => 'a.m.',
+ '㏃' => 'Bq',
+ '㏄' => 'cc',
+ '㏅' => 'cd',
+ '㏆' => 'C∕kg',
+ '㏇' => 'Co.',
+ '㏈' => 'dB',
+ '㏉' => 'Gy',
+ '㏊' => 'ha',
+ '㏋' => 'HP',
+ '㏌' => 'in',
+ '㏍' => 'KK',
+ '㏎' => 'KM',
+ '㏏' => 'kt',
+ '㏐' => 'lm',
+ '㏑' => 'ln',
+ '㏒' => 'log',
+ '㏓' => 'lx',
+ '㏔' => 'mb',
+ '㏕' => 'mil',
+ '㏖' => 'mol',
+ '㏗' => 'PH',
+ '㏘' => 'p.m.',
+ '㏙' => 'PPM',
+ '㏚' => 'PR',
+ '㏛' => 'sr',
+ '㏜' => 'Sv',
+ '㏝' => 'Wb',
+ '㏞' => 'V∕m',
+ '㏟' => 'A∕m',
+ '㏠' => '1日',
+ '㏡' => '2日',
+ '㏢' => '3日',
+ '㏣' => '4日',
+ '㏤' => '5日',
+ '㏥' => '6日',
+ '㏦' => '7日',
+ '㏧' => '8日',
+ '㏨' => '9日',
+ '㏩' => '10日',
+ '㏪' => '11日',
+ '㏫' => '12日',
+ '㏬' => '13日',
+ '㏭' => '14日',
+ '㏮' => '15日',
+ '㏯' => '16日',
+ '㏰' => '17日',
+ '㏱' => '18日',
+ '㏲' => '19日',
+ '㏳' => '20日',
+ '㏴' => '21日',
+ '㏵' => '22日',
+ '㏶' => '23日',
+ '㏷' => '24日',
+ '㏸' => '25日',
+ '㏹' => '26日',
+ '㏺' => '27日',
+ '㏻' => '28日',
+ '㏼' => '29日',
+ '㏽' => '30日',
+ '㏾' => '31日',
+ '㏿' => 'gal',
+ 'ꚜ' => 'ъ',
+ 'ꚝ' => 'ь',
+ 'ꝰ' => 'ꝯ',
+ 'ꟸ' => 'Ħ',
+ 'ꟹ' => 'œ',
+ 'ꭜ' => 'ꜧ',
+ 'ꭝ' => 'ꬷ',
+ 'ꭞ' => 'ɫ',
+ 'ꭟ' => 'ꭒ',
+ 'ꭩ' => 'ʍ',
+ 'ff' => 'ff',
+ 'fi' => 'fi',
+ 'fl' => 'fl',
+ 'ffi' => 'ffi',
+ 'ffl' => 'ffl',
+ 'ſt' => 'st',
+ 'st' => 'st',
+ 'ﬓ' => 'մն',
+ 'ﬔ' => 'մե',
+ 'ﬕ' => 'մի',
+ 'ﬖ' => 'վն',
+ 'ﬗ' => 'մխ',
+ 'ﬠ' => 'ע',
+ 'ﬡ' => 'א',
+ 'ﬢ' => 'ד',
+ 'ﬣ' => 'ה',
+ 'ﬤ' => 'כ',
+ 'ﬥ' => 'ל',
+ 'ﬦ' => 'ם',
+ 'ﬧ' => 'ר',
+ 'ﬨ' => 'ת',
+ '﬩' => '+',
+ 'ﭏ' => 'אל',
+ 'ﭐ' => 'ٱ',
+ 'ﭑ' => 'ٱ',
+ 'ﭒ' => 'ٻ',
+ 'ﭓ' => 'ٻ',
+ 'ﭔ' => 'ٻ',
+ 'ﭕ' => 'ٻ',
+ 'ﭖ' => 'پ',
+ 'ﭗ' => 'پ',
+ 'ﭘ' => 'پ',
+ 'ﭙ' => 'پ',
+ 'ﭚ' => 'ڀ',
+ 'ﭛ' => 'ڀ',
+ 'ﭜ' => 'ڀ',
+ 'ﭝ' => 'ڀ',
+ 'ﭞ' => 'ٺ',
+ 'ﭟ' => 'ٺ',
+ 'ﭠ' => 'ٺ',
+ 'ﭡ' => 'ٺ',
+ 'ﭢ' => 'ٿ',
+ 'ﭣ' => 'ٿ',
+ 'ﭤ' => 'ٿ',
+ 'ﭥ' => 'ٿ',
+ 'ﭦ' => 'ٹ',
+ 'ﭧ' => 'ٹ',
+ 'ﭨ' => 'ٹ',
+ 'ﭩ' => 'ٹ',
+ 'ﭪ' => 'ڤ',
+ 'ﭫ' => 'ڤ',
+ 'ﭬ' => 'ڤ',
+ 'ﭭ' => 'ڤ',
+ 'ﭮ' => 'ڦ',
+ 'ﭯ' => 'ڦ',
+ 'ﭰ' => 'ڦ',
+ 'ﭱ' => 'ڦ',
+ 'ﭲ' => 'ڄ',
+ 'ﭳ' => 'ڄ',
+ 'ﭴ' => 'ڄ',
+ 'ﭵ' => 'ڄ',
+ 'ﭶ' => 'ڃ',
+ 'ﭷ' => 'ڃ',
+ 'ﭸ' => 'ڃ',
+ 'ﭹ' => 'ڃ',
+ 'ﭺ' => 'چ',
+ 'ﭻ' => 'چ',
+ 'ﭼ' => 'چ',
+ 'ﭽ' => 'چ',
+ 'ﭾ' => 'ڇ',
+ 'ﭿ' => 'ڇ',
+ 'ﮀ' => 'ڇ',
+ 'ﮁ' => 'ڇ',
+ 'ﮂ' => 'ڍ',
+ 'ﮃ' => 'ڍ',
+ 'ﮄ' => 'ڌ',
+ 'ﮅ' => 'ڌ',
+ 'ﮆ' => 'ڎ',
+ 'ﮇ' => 'ڎ',
+ 'ﮈ' => 'ڈ',
+ 'ﮉ' => 'ڈ',
+ 'ﮊ' => 'ژ',
+ 'ﮋ' => 'ژ',
+ 'ﮌ' => 'ڑ',
+ 'ﮍ' => 'ڑ',
+ 'ﮎ' => 'ک',
+ 'ﮏ' => 'ک',
+ 'ﮐ' => 'ک',
+ 'ﮑ' => 'ک',
+ 'ﮒ' => 'گ',
+ 'ﮓ' => 'گ',
+ 'ﮔ' => 'گ',
+ 'ﮕ' => 'گ',
+ 'ﮖ' => 'ڳ',
+ 'ﮗ' => 'ڳ',
+ 'ﮘ' => 'ڳ',
+ 'ﮙ' => 'ڳ',
+ 'ﮚ' => 'ڱ',
+ 'ﮛ' => 'ڱ',
+ 'ﮜ' => 'ڱ',
+ 'ﮝ' => 'ڱ',
+ 'ﮞ' => 'ں',
+ 'ﮟ' => 'ں',
+ 'ﮠ' => 'ڻ',
+ 'ﮡ' => 'ڻ',
+ 'ﮢ' => 'ڻ',
+ 'ﮣ' => 'ڻ',
+ 'ﮤ' => 'ۀ',
+ 'ﮥ' => 'ۀ',
+ 'ﮦ' => 'ہ',
+ 'ﮧ' => 'ہ',
+ 'ﮨ' => 'ہ',
+ 'ﮩ' => 'ہ',
+ 'ﮪ' => 'ھ',
+ 'ﮫ' => 'ھ',
+ 'ﮬ' => 'ھ',
+ 'ﮭ' => 'ھ',
+ 'ﮮ' => 'ے',
+ 'ﮯ' => 'ے',
+ 'ﮰ' => 'ۓ',
+ 'ﮱ' => 'ۓ',
+ 'ﯓ' => 'ڭ',
+ 'ﯔ' => 'ڭ',
+ 'ﯕ' => 'ڭ',
+ 'ﯖ' => 'ڭ',
+ 'ﯗ' => 'ۇ',
+ 'ﯘ' => 'ۇ',
+ 'ﯙ' => 'ۆ',
+ 'ﯚ' => 'ۆ',
+ 'ﯛ' => 'ۈ',
+ 'ﯜ' => 'ۈ',
+ 'ﯝ' => 'ۇٴ',
+ 'ﯞ' => 'ۋ',
+ 'ﯟ' => 'ۋ',
+ 'ﯠ' => 'ۅ',
+ 'ﯡ' => 'ۅ',
+ 'ﯢ' => 'ۉ',
+ 'ﯣ' => 'ۉ',
+ 'ﯤ' => 'ې',
+ 'ﯥ' => 'ې',
+ 'ﯦ' => 'ې',
+ 'ﯧ' => 'ې',
+ 'ﯨ' => 'ى',
+ 'ﯩ' => 'ى',
+ 'ﯪ' => 'ئا',
+ 'ﯫ' => 'ئا',
+ 'ﯬ' => 'ئە',
+ 'ﯭ' => 'ئە',
+ 'ﯮ' => 'ئو',
+ 'ﯯ' => 'ئو',
+ 'ﯰ' => 'ئۇ',
+ 'ﯱ' => 'ئۇ',
+ 'ﯲ' => 'ئۆ',
+ 'ﯳ' => 'ئۆ',
+ 'ﯴ' => 'ئۈ',
+ 'ﯵ' => 'ئۈ',
+ 'ﯶ' => 'ئې',
+ 'ﯷ' => 'ئې',
+ 'ﯸ' => 'ئې',
+ 'ﯹ' => 'ئى',
+ 'ﯺ' => 'ئى',
+ 'ﯻ' => 'ئى',
+ 'ﯼ' => 'ی',
+ 'ﯽ' => 'ی',
+ 'ﯾ' => 'ی',
+ 'ﯿ' => 'ی',
+ 'ﰀ' => 'ئج',
+ 'ﰁ' => 'ئح',
+ 'ﰂ' => 'ئم',
+ 'ﰃ' => 'ئى',
+ 'ﰄ' => 'ئي',
+ 'ﰅ' => 'بج',
+ 'ﰆ' => 'بح',
+ 'ﰇ' => 'بخ',
+ 'ﰈ' => 'بم',
+ 'ﰉ' => 'بى',
+ 'ﰊ' => 'بي',
+ 'ﰋ' => 'تج',
+ 'ﰌ' => 'تح',
+ 'ﰍ' => 'تخ',
+ 'ﰎ' => 'تم',
+ 'ﰏ' => 'تى',
+ 'ﰐ' => 'تي',
+ 'ﰑ' => 'ثج',
+ 'ﰒ' => 'ثم',
+ 'ﰓ' => 'ثى',
+ 'ﰔ' => 'ثي',
+ 'ﰕ' => 'جح',
+ 'ﰖ' => 'جم',
+ 'ﰗ' => 'حج',
+ 'ﰘ' => 'حم',
+ 'ﰙ' => 'خج',
+ 'ﰚ' => 'خح',
+ 'ﰛ' => 'خم',
+ 'ﰜ' => 'سج',
+ 'ﰝ' => 'سح',
+ 'ﰞ' => 'سخ',
+ 'ﰟ' => 'سم',
+ 'ﰠ' => 'صح',
+ 'ﰡ' => 'صم',
+ 'ﰢ' => 'ضج',
+ 'ﰣ' => 'ضح',
+ 'ﰤ' => 'ضخ',
+ 'ﰥ' => 'ضم',
+ 'ﰦ' => 'طح',
+ 'ﰧ' => 'طم',
+ 'ﰨ' => 'ظم',
+ 'ﰩ' => 'عج',
+ 'ﰪ' => 'عم',
+ 'ﰫ' => 'غج',
+ 'ﰬ' => 'غم',
+ 'ﰭ' => 'فج',
+ 'ﰮ' => 'فح',
+ 'ﰯ' => 'فخ',
+ 'ﰰ' => 'فم',
+ 'ﰱ' => 'فى',
+ 'ﰲ' => 'في',
+ 'ﰳ' => 'قح',
+ 'ﰴ' => 'قم',
+ 'ﰵ' => 'قى',
+ 'ﰶ' => 'قي',
+ 'ﰷ' => 'كا',
+ 'ﰸ' => 'كج',
+ 'ﰹ' => 'كح',
+ 'ﰺ' => 'كخ',
+ 'ﰻ' => 'كل',
+ 'ﰼ' => 'كم',
+ 'ﰽ' => 'كى',
+ 'ﰾ' => 'كي',
+ 'ﰿ' => 'لج',
+ 'ﱀ' => 'لح',
+ 'ﱁ' => 'لخ',
+ 'ﱂ' => 'لم',
+ 'ﱃ' => 'لى',
+ 'ﱄ' => 'لي',
+ 'ﱅ' => 'مج',
+ 'ﱆ' => 'مح',
+ 'ﱇ' => 'مخ',
+ 'ﱈ' => 'مم',
+ 'ﱉ' => 'مى',
+ 'ﱊ' => 'مي',
+ 'ﱋ' => 'نج',
+ 'ﱌ' => 'نح',
+ 'ﱍ' => 'نخ',
+ 'ﱎ' => 'نم',
+ 'ﱏ' => 'نى',
+ 'ﱐ' => 'ني',
+ 'ﱑ' => 'هج',
+ 'ﱒ' => 'هم',
+ 'ﱓ' => 'هى',
+ 'ﱔ' => 'هي',
+ 'ﱕ' => 'يج',
+ 'ﱖ' => 'يح',
+ 'ﱗ' => 'يخ',
+ 'ﱘ' => 'يم',
+ 'ﱙ' => 'يى',
+ 'ﱚ' => 'يي',
+ 'ﱛ' => 'ذٰ',
+ 'ﱜ' => 'رٰ',
+ 'ﱝ' => 'ىٰ',
+ 'ﱞ' => ' ٌّ',
+ 'ﱟ' => ' ٍّ',
+ 'ﱠ' => ' َّ',
+ 'ﱡ' => ' ُّ',
+ 'ﱢ' => ' ِّ',
+ 'ﱣ' => ' ّٰ',
+ 'ﱤ' => 'ئر',
+ 'ﱥ' => 'ئز',
+ 'ﱦ' => 'ئم',
+ 'ﱧ' => 'ئن',
+ 'ﱨ' => 'ئى',
+ 'ﱩ' => 'ئي',
+ 'ﱪ' => 'بر',
+ 'ﱫ' => 'بز',
+ 'ﱬ' => 'بم',
+ 'ﱭ' => 'بن',
+ 'ﱮ' => 'بى',
+ 'ﱯ' => 'بي',
+ 'ﱰ' => 'تر',
+ 'ﱱ' => 'تز',
+ 'ﱲ' => 'تم',
+ 'ﱳ' => 'تن',
+ 'ﱴ' => 'تى',
+ 'ﱵ' => 'تي',
+ 'ﱶ' => 'ثر',
+ 'ﱷ' => 'ثز',
+ 'ﱸ' => 'ثم',
+ 'ﱹ' => 'ثن',
+ 'ﱺ' => 'ثى',
+ 'ﱻ' => 'ثي',
+ 'ﱼ' => 'فى',
+ 'ﱽ' => 'في',
+ 'ﱾ' => 'قى',
+ 'ﱿ' => 'قي',
+ 'ﲀ' => 'كا',
+ 'ﲁ' => 'كل',
+ 'ﲂ' => 'كم',
+ 'ﲃ' => 'كى',
+ 'ﲄ' => 'كي',
+ 'ﲅ' => 'لم',
+ 'ﲆ' => 'لى',
+ 'ﲇ' => 'لي',
+ 'ﲈ' => 'ما',
+ 'ﲉ' => 'مم',
+ 'ﲊ' => 'نر',
+ 'ﲋ' => 'نز',
+ 'ﲌ' => 'نم',
+ 'ﲍ' => 'نن',
+ 'ﲎ' => 'نى',
+ 'ﲏ' => 'ني',
+ 'ﲐ' => 'ىٰ',
+ 'ﲑ' => 'ير',
+ 'ﲒ' => 'يز',
+ 'ﲓ' => 'يم',
+ 'ﲔ' => 'ين',
+ 'ﲕ' => 'يى',
+ 'ﲖ' => 'يي',
+ 'ﲗ' => 'ئج',
+ 'ﲘ' => 'ئح',
+ 'ﲙ' => 'ئخ',
+ 'ﲚ' => 'ئم',
+ 'ﲛ' => 'ئه',
+ 'ﲜ' => 'بج',
+ 'ﲝ' => 'بح',
+ 'ﲞ' => 'بخ',
+ 'ﲟ' => 'بم',
+ 'ﲠ' => 'به',
+ 'ﲡ' => 'تج',
+ 'ﲢ' => 'تح',
+ 'ﲣ' => 'تخ',
+ 'ﲤ' => 'تم',
+ 'ﲥ' => 'ته',
+ 'ﲦ' => 'ثم',
+ 'ﲧ' => 'جح',
+ 'ﲨ' => 'جم',
+ 'ﲩ' => 'حج',
+ 'ﲪ' => 'حم',
+ 'ﲫ' => 'خج',
+ 'ﲬ' => 'خم',
+ 'ﲭ' => 'سج',
+ 'ﲮ' => 'سح',
+ 'ﲯ' => 'سخ',
+ 'ﲰ' => 'سم',
+ 'ﲱ' => 'صح',
+ 'ﲲ' => 'صخ',
+ 'ﲳ' => 'صم',
+ 'ﲴ' => 'ضج',
+ 'ﲵ' => 'ضح',
+ 'ﲶ' => 'ضخ',
+ 'ﲷ' => 'ضم',
+ 'ﲸ' => 'طح',
+ 'ﲹ' => 'ظم',
+ 'ﲺ' => 'عج',
+ 'ﲻ' => 'عم',
+ 'ﲼ' => 'غج',
+ 'ﲽ' => 'غم',
+ 'ﲾ' => 'فج',
+ 'ﲿ' => 'فح',
+ 'ﳀ' => 'فخ',
+ 'ﳁ' => 'فم',
+ 'ﳂ' => 'قح',
+ 'ﳃ' => 'قم',
+ 'ﳄ' => 'كج',
+ 'ﳅ' => 'كح',
+ 'ﳆ' => 'كخ',
+ 'ﳇ' => 'كل',
+ 'ﳈ' => 'كم',
+ 'ﳉ' => 'لج',
+ 'ﳊ' => 'لح',
+ 'ﳋ' => 'لخ',
+ 'ﳌ' => 'لم',
+ 'ﳍ' => 'له',
+ 'ﳎ' => 'مج',
+ 'ﳏ' => 'مح',
+ 'ﳐ' => 'مخ',
+ 'ﳑ' => 'مم',
+ 'ﳒ' => 'نج',
+ 'ﳓ' => 'نح',
+ 'ﳔ' => 'نخ',
+ 'ﳕ' => 'نم',
+ 'ﳖ' => 'نه',
+ 'ﳗ' => 'هج',
+ 'ﳘ' => 'هم',
+ 'ﳙ' => 'هٰ',
+ 'ﳚ' => 'يج',
+ 'ﳛ' => 'يح',
+ 'ﳜ' => 'يخ',
+ 'ﳝ' => 'يم',
+ 'ﳞ' => 'يه',
+ 'ﳟ' => 'ئم',
+ 'ﳠ' => 'ئه',
+ 'ﳡ' => 'بم',
+ 'ﳢ' => 'به',
+ 'ﳣ' => 'تم',
+ 'ﳤ' => 'ته',
+ 'ﳥ' => 'ثم',
+ 'ﳦ' => 'ثه',
+ 'ﳧ' => 'سم',
+ 'ﳨ' => 'سه',
+ 'ﳩ' => 'شم',
+ 'ﳪ' => 'شه',
+ 'ﳫ' => 'كل',
+ 'ﳬ' => 'كم',
+ 'ﳭ' => 'لم',
+ 'ﳮ' => 'نم',
+ 'ﳯ' => 'نه',
+ 'ﳰ' => 'يم',
+ 'ﳱ' => 'يه',
+ 'ﳲ' => 'ـَّ',
+ 'ﳳ' => 'ـُّ',
+ 'ﳴ' => 'ـِّ',
+ 'ﳵ' => 'طى',
+ 'ﳶ' => 'طي',
+ 'ﳷ' => 'عى',
+ 'ﳸ' => 'عي',
+ 'ﳹ' => 'غى',
+ 'ﳺ' => 'غي',
+ 'ﳻ' => 'سى',
+ 'ﳼ' => 'سي',
+ 'ﳽ' => 'شى',
+ 'ﳾ' => 'شي',
+ 'ﳿ' => 'حى',
+ 'ﴀ' => 'حي',
+ 'ﴁ' => 'جى',
+ 'ﴂ' => 'جي',
+ 'ﴃ' => 'خى',
+ 'ﴄ' => 'خي',
+ 'ﴅ' => 'صى',
+ 'ﴆ' => 'صي',
+ 'ﴇ' => 'ضى',
+ 'ﴈ' => 'ضي',
+ 'ﴉ' => 'شج',
+ 'ﴊ' => 'شح',
+ 'ﴋ' => 'شخ',
+ 'ﴌ' => 'شم',
+ 'ﴍ' => 'شر',
+ 'ﴎ' => 'سر',
+ 'ﴏ' => 'صر',
+ 'ﴐ' => 'ضر',
+ 'ﴑ' => 'طى',
+ 'ﴒ' => 'طي',
+ 'ﴓ' => 'عى',
+ 'ﴔ' => 'عي',
+ 'ﴕ' => 'غى',
+ 'ﴖ' => 'غي',
+ 'ﴗ' => 'سى',
+ 'ﴘ' => 'سي',
+ 'ﴙ' => 'شى',
+ 'ﴚ' => 'شي',
+ 'ﴛ' => 'حى',
+ 'ﴜ' => 'حي',
+ 'ﴝ' => 'جى',
+ 'ﴞ' => 'جي',
+ 'ﴟ' => 'خى',
+ 'ﴠ' => 'خي',
+ 'ﴡ' => 'صى',
+ 'ﴢ' => 'صي',
+ 'ﴣ' => 'ضى',
+ 'ﴤ' => 'ضي',
+ 'ﴥ' => 'شج',
+ 'ﴦ' => 'شح',
+ 'ﴧ' => 'شخ',
+ 'ﴨ' => 'شم',
+ 'ﴩ' => 'شر',
+ 'ﴪ' => 'سر',
+ 'ﴫ' => 'صر',
+ 'ﴬ' => 'ضر',
+ 'ﴭ' => 'شج',
+ 'ﴮ' => 'شح',
+ 'ﴯ' => 'شخ',
+ 'ﴰ' => 'شم',
+ 'ﴱ' => 'سه',
+ 'ﴲ' => 'شه',
+ 'ﴳ' => 'طم',
+ 'ﴴ' => 'سج',
+ 'ﴵ' => 'سح',
+ 'ﴶ' => 'سخ',
+ 'ﴷ' => 'شج',
+ 'ﴸ' => 'شح',
+ 'ﴹ' => 'شخ',
+ 'ﴺ' => 'طم',
+ 'ﴻ' => 'ظم',
+ 'ﴼ' => 'اً',
+ 'ﴽ' => 'اً',
+ 'ﵐ' => 'تجم',
+ 'ﵑ' => 'تحج',
+ 'ﵒ' => 'تحج',
+ 'ﵓ' => 'تحم',
+ 'ﵔ' => 'تخم',
+ 'ﵕ' => 'تمج',
+ 'ﵖ' => 'تمح',
+ 'ﵗ' => 'تمخ',
+ 'ﵘ' => 'جمح',
+ 'ﵙ' => 'جمح',
+ 'ﵚ' => 'حمي',
+ 'ﵛ' => 'حمى',
+ 'ﵜ' => 'سحج',
+ 'ﵝ' => 'سجح',
+ 'ﵞ' => 'سجى',
+ 'ﵟ' => 'سمح',
+ 'ﵠ' => 'سمح',
+ 'ﵡ' => 'سمج',
+ 'ﵢ' => 'سمم',
+ 'ﵣ' => 'سمم',
+ 'ﵤ' => 'صحح',
+ 'ﵥ' => 'صحح',
+ 'ﵦ' => 'صمم',
+ 'ﵧ' => 'شحم',
+ 'ﵨ' => 'شحم',
+ 'ﵩ' => 'شجي',
+ 'ﵪ' => 'شمخ',
+ 'ﵫ' => 'شمخ',
+ 'ﵬ' => 'شمم',
+ 'ﵭ' => 'شمم',
+ 'ﵮ' => 'ضحى',
+ 'ﵯ' => 'ضخم',
+ 'ﵰ' => 'ضخم',
+ 'ﵱ' => 'طمح',
+ 'ﵲ' => 'طمح',
+ 'ﵳ' => 'طمم',
+ 'ﵴ' => 'طمي',
+ 'ﵵ' => 'عجم',
+ 'ﵶ' => 'عمم',
+ 'ﵷ' => 'عمم',
+ 'ﵸ' => 'عمى',
+ 'ﵹ' => 'غمم',
+ 'ﵺ' => 'غمي',
+ 'ﵻ' => 'غمى',
+ 'ﵼ' => 'فخم',
+ 'ﵽ' => 'فخم',
+ 'ﵾ' => 'قمح',
+ 'ﵿ' => 'قمم',
+ 'ﶀ' => 'لحم',
+ 'ﶁ' => 'لحي',
+ 'ﶂ' => 'لحى',
+ 'ﶃ' => 'لجج',
+ 'ﶄ' => 'لجج',
+ 'ﶅ' => 'لخم',
+ 'ﶆ' => 'لخم',
+ 'ﶇ' => 'لمح',
+ 'ﶈ' => 'لمح',
+ 'ﶉ' => 'محج',
+ 'ﶊ' => 'محم',
+ 'ﶋ' => 'محي',
+ 'ﶌ' => 'مجح',
+ 'ﶍ' => 'مجم',
+ 'ﶎ' => 'مخج',
+ 'ﶏ' => 'مخم',
+ 'ﶒ' => 'مجخ',
+ 'ﶓ' => 'همج',
+ 'ﶔ' => 'همم',
+ 'ﶕ' => 'نحم',
+ 'ﶖ' => 'نحى',
+ 'ﶗ' => 'نجم',
+ 'ﶘ' => 'نجم',
+ 'ﶙ' => 'نجى',
+ 'ﶚ' => 'نمي',
+ 'ﶛ' => 'نمى',
+ 'ﶜ' => 'يمم',
+ 'ﶝ' => 'يمم',
+ 'ﶞ' => 'بخي',
+ 'ﶟ' => 'تجي',
+ 'ﶠ' => 'تجى',
+ 'ﶡ' => 'تخي',
+ 'ﶢ' => 'تخى',
+ 'ﶣ' => 'تمي',
+ 'ﶤ' => 'تمى',
+ 'ﶥ' => 'جمي',
+ 'ﶦ' => 'جحى',
+ 'ﶧ' => 'جمى',
+ 'ﶨ' => 'سخى',
+ 'ﶩ' => 'صحي',
+ 'ﶪ' => 'شحي',
+ 'ﶫ' => 'ضحي',
+ 'ﶬ' => 'لجي',
+ 'ﶭ' => 'لمي',
+ 'ﶮ' => 'يحي',
+ 'ﶯ' => 'يجي',
+ 'ﶰ' => 'يمي',
+ 'ﶱ' => 'ممي',
+ 'ﶲ' => 'قمي',
+ 'ﶳ' => 'نحي',
+ 'ﶴ' => 'قمح',
+ 'ﶵ' => 'لحم',
+ 'ﶶ' => 'عمي',
+ 'ﶷ' => 'كمي',
+ 'ﶸ' => 'نجح',
+ 'ﶹ' => 'مخي',
+ 'ﶺ' => 'لجم',
+ 'ﶻ' => 'كمم',
+ 'ﶼ' => 'لجم',
+ 'ﶽ' => 'نجح',
+ 'ﶾ' => 'جحي',
+ 'ﶿ' => 'حجي',
+ 'ﷀ' => 'مجي',
+ 'ﷁ' => 'فمي',
+ 'ﷂ' => 'بحي',
+ 'ﷃ' => 'كمم',
+ 'ﷄ' => 'عجم',
+ 'ﷅ' => 'صمم',
+ 'ﷆ' => 'سخي',
+ 'ﷇ' => 'نجي',
+ 'ﷰ' => 'صلے',
+ 'ﷱ' => 'قلے',
+ 'ﷲ' => 'الله',
+ 'ﷳ' => 'اكبر',
+ 'ﷴ' => 'محمد',
+ 'ﷵ' => 'صلعم',
+ 'ﷶ' => 'رسول',
+ 'ﷷ' => 'عليه',
+ 'ﷸ' => 'وسلم',
+ 'ﷹ' => 'صلى',
+ 'ﷺ' => 'صلى الله عليه وسلم',
+ 'ﷻ' => 'جل جلاله',
+ '﷼' => 'ریال',
+ '︐' => ',',
+ '︑' => '、',
+ '︒' => '。',
+ '︓' => ':',
+ '︔' => ';',
+ '︕' => '!',
+ '︖' => '?',
+ '︗' => '〖',
+ '︘' => '〗',
+ '︙' => '...',
+ '︰' => '..',
+ '︱' => '—',
+ '︲' => '–',
+ '︳' => '_',
+ '︴' => '_',
+ '︵' => '(',
+ '︶' => ')',
+ '︷' => '{',
+ '︸' => '}',
+ '︹' => '〔',
+ '︺' => '〕',
+ '︻' => '【',
+ '︼' => '】',
+ '︽' => '《',
+ '︾' => '》',
+ '︿' => '〈',
+ '﹀' => '〉',
+ '﹁' => '「',
+ '﹂' => '」',
+ '﹃' => '『',
+ '﹄' => '』',
+ '﹇' => '[',
+ '﹈' => ']',
+ '﹉' => ' ̅',
+ '﹊' => ' ̅',
+ '﹋' => ' ̅',
+ '﹌' => ' ̅',
+ '﹍' => '_',
+ '﹎' => '_',
+ '﹏' => '_',
+ '﹐' => ',',
+ '﹑' => '、',
+ '﹒' => '.',
+ '﹔' => ';',
+ '﹕' => ':',
+ '﹖' => '?',
+ '﹗' => '!',
+ '﹘' => '—',
+ '﹙' => '(',
+ '﹚' => ')',
+ '﹛' => '{',
+ '﹜' => '}',
+ '﹝' => '〔',
+ '﹞' => '〕',
+ '﹟' => '#',
+ '﹠' => '&',
+ '﹡' => '*',
+ '﹢' => '+',
+ '﹣' => '-',
+ '﹤' => '<',
+ '﹥' => '>',
+ '﹦' => '=',
+ '﹨' => '\\',
+ '﹩' => '$',
+ '﹪' => '%',
+ '﹫' => '@',
+ 'ﹰ' => ' ً',
+ 'ﹱ' => 'ـً',
+ 'ﹲ' => ' ٌ',
+ 'ﹴ' => ' ٍ',
+ 'ﹶ' => ' َ',
+ 'ﹷ' => 'ـَ',
+ 'ﹸ' => ' ُ',
+ 'ﹹ' => 'ـُ',
+ 'ﹺ' => ' ِ',
+ 'ﹻ' => 'ـِ',
+ 'ﹼ' => ' ّ',
+ 'ﹽ' => 'ـّ',
+ 'ﹾ' => ' ْ',
+ 'ﹿ' => 'ـْ',
+ 'ﺀ' => 'ء',
+ 'ﺁ' => 'آ',
+ 'ﺂ' => 'آ',
+ 'ﺃ' => 'أ',
+ 'ﺄ' => 'أ',
+ 'ﺅ' => 'ؤ',
+ 'ﺆ' => 'ؤ',
+ 'ﺇ' => 'إ',
+ 'ﺈ' => 'إ',
+ 'ﺉ' => 'ئ',
+ 'ﺊ' => 'ئ',
+ 'ﺋ' => 'ئ',
+ 'ﺌ' => 'ئ',
+ 'ﺍ' => 'ا',
+ 'ﺎ' => 'ا',
+ 'ﺏ' => 'ب',
+ 'ﺐ' => 'ب',
+ 'ﺑ' => 'ب',
+ 'ﺒ' => 'ب',
+ 'ﺓ' => 'ة',
+ 'ﺔ' => 'ة',
+ 'ﺕ' => 'ت',
+ 'ﺖ' => 'ت',
+ 'ﺗ' => 'ت',
+ 'ﺘ' => 'ت',
+ 'ﺙ' => 'ث',
+ 'ﺚ' => 'ث',
+ 'ﺛ' => 'ث',
+ 'ﺜ' => 'ث',
+ 'ﺝ' => 'ج',
+ 'ﺞ' => 'ج',
+ 'ﺟ' => 'ج',
+ 'ﺠ' => 'ج',
+ 'ﺡ' => 'ح',
+ 'ﺢ' => 'ح',
+ 'ﺣ' => 'ح',
+ 'ﺤ' => 'ح',
+ 'ﺥ' => 'خ',
+ 'ﺦ' => 'خ',
+ 'ﺧ' => 'خ',
+ 'ﺨ' => 'خ',
+ 'ﺩ' => 'د',
+ 'ﺪ' => 'د',
+ 'ﺫ' => 'ذ',
+ 'ﺬ' => 'ذ',
+ 'ﺭ' => 'ر',
+ 'ﺮ' => 'ر',
+ 'ﺯ' => 'ز',
+ 'ﺰ' => 'ز',
+ 'ﺱ' => 'س',
+ 'ﺲ' => 'س',
+ 'ﺳ' => 'س',
+ 'ﺴ' => 'س',
+ 'ﺵ' => 'ش',
+ 'ﺶ' => 'ش',
+ 'ﺷ' => 'ش',
+ 'ﺸ' => 'ش',
+ 'ﺹ' => 'ص',
+ 'ﺺ' => 'ص',
+ 'ﺻ' => 'ص',
+ 'ﺼ' => 'ص',
+ 'ﺽ' => 'ض',
+ 'ﺾ' => 'ض',
+ 'ﺿ' => 'ض',
+ 'ﻀ' => 'ض',
+ 'ﻁ' => 'ط',
+ 'ﻂ' => 'ط',
+ 'ﻃ' => 'ط',
+ 'ﻄ' => 'ط',
+ 'ﻅ' => 'ظ',
+ 'ﻆ' => 'ظ',
+ 'ﻇ' => 'ظ',
+ 'ﻈ' => 'ظ',
+ 'ﻉ' => 'ع',
+ 'ﻊ' => 'ع',
+ 'ﻋ' => 'ع',
+ 'ﻌ' => 'ع',
+ 'ﻍ' => 'غ',
+ 'ﻎ' => 'غ',
+ 'ﻏ' => 'غ',
+ 'ﻐ' => 'غ',
+ 'ﻑ' => 'ف',
+ 'ﻒ' => 'ف',
+ 'ﻓ' => 'ف',
+ 'ﻔ' => 'ف',
+ 'ﻕ' => 'ق',
+ 'ﻖ' => 'ق',
+ 'ﻗ' => 'ق',
+ 'ﻘ' => 'ق',
+ 'ﻙ' => 'ك',
+ 'ﻚ' => 'ك',
+ 'ﻛ' => 'ك',
+ 'ﻜ' => 'ك',
+ 'ﻝ' => 'ل',
+ 'ﻞ' => 'ل',
+ 'ﻟ' => 'ل',
+ 'ﻠ' => 'ل',
+ 'ﻡ' => 'م',
+ 'ﻢ' => 'م',
+ 'ﻣ' => 'م',
+ 'ﻤ' => 'م',
+ 'ﻥ' => 'ن',
+ 'ﻦ' => 'ن',
+ 'ﻧ' => 'ن',
+ 'ﻨ' => 'ن',
+ 'ﻩ' => 'ه',
+ 'ﻪ' => 'ه',
+ 'ﻫ' => 'ه',
+ 'ﻬ' => 'ه',
+ 'ﻭ' => 'و',
+ 'ﻮ' => 'و',
+ 'ﻯ' => 'ى',
+ 'ﻰ' => 'ى',
+ 'ﻱ' => 'ي',
+ 'ﻲ' => 'ي',
+ 'ﻳ' => 'ي',
+ 'ﻴ' => 'ي',
+ 'ﻵ' => 'لآ',
+ 'ﻶ' => 'لآ',
+ 'ﻷ' => 'لأ',
+ 'ﻸ' => 'لأ',
+ 'ﻹ' => 'لإ',
+ 'ﻺ' => 'لإ',
+ 'ﻻ' => 'لا',
+ 'ﻼ' => 'لا',
+ '!' => '!',
+ '"' => '"',
+ '#' => '#',
+ '$' => '$',
+ '%' => '%',
+ '&' => '&',
+ ''' => '\'',
+ '(' => '(',
+ ')' => ')',
+ '*' => '*',
+ '+' => '+',
+ ',' => ',',
+ '-' => '-',
+ '.' => '.',
+ '/' => '/',
+ '0' => '0',
+ '1' => '1',
+ '2' => '2',
+ '3' => '3',
+ '4' => '4',
+ '5' => '5',
+ '6' => '6',
+ '7' => '7',
+ '8' => '8',
+ '9' => '9',
+ ':' => ':',
+ ';' => ';',
+ '<' => '<',
+ '=' => '=',
+ '>' => '>',
+ '?' => '?',
+ '@' => '@',
+ 'A' => 'A',
+ 'B' => 'B',
+ 'C' => 'C',
+ 'D' => 'D',
+ 'E' => 'E',
+ 'F' => 'F',
+ 'G' => 'G',
+ 'H' => 'H',
+ 'I' => 'I',
+ 'J' => 'J',
+ 'K' => 'K',
+ 'L' => 'L',
+ 'M' => 'M',
+ 'N' => 'N',
+ 'O' => 'O',
+ 'P' => 'P',
+ 'Q' => 'Q',
+ 'R' => 'R',
+ 'S' => 'S',
+ 'T' => 'T',
+ 'U' => 'U',
+ 'V' => 'V',
+ 'W' => 'W',
+ 'X' => 'X',
+ 'Y' => 'Y',
+ 'Z' => 'Z',
+ '[' => '[',
+ '\' => '\\',
+ ']' => ']',
+ '^' => '^',
+ '_' => '_',
+ '`' => '`',
+ 'a' => 'a',
+ 'b' => 'b',
+ 'c' => 'c',
+ 'd' => 'd',
+ 'e' => 'e',
+ 'f' => 'f',
+ 'g' => 'g',
+ 'h' => 'h',
+ 'i' => 'i',
+ 'j' => 'j',
+ 'k' => 'k',
+ 'l' => 'l',
+ 'm' => 'm',
+ 'n' => 'n',
+ 'o' => 'o',
+ 'p' => 'p',
+ 'q' => 'q',
+ 'r' => 'r',
+ 's' => 's',
+ 't' => 't',
+ 'u' => 'u',
+ 'v' => 'v',
+ 'w' => 'w',
+ 'x' => 'x',
+ 'y' => 'y',
+ 'z' => 'z',
+ '{' => '{',
+ '|' => '|',
+ '}' => '}',
+ '~' => '~',
+ '⦅' => '⦅',
+ '⦆' => '⦆',
+ '。' => '。',
+ '「' => '「',
+ '」' => '」',
+ '、' => '、',
+ '・' => '・',
+ 'ヲ' => 'ヲ',
+ 'ァ' => 'ァ',
+ 'ィ' => 'ィ',
+ 'ゥ' => 'ゥ',
+ 'ェ' => 'ェ',
+ 'ォ' => 'ォ',
+ 'ャ' => 'ャ',
+ 'ュ' => 'ュ',
+ 'ョ' => 'ョ',
+ 'ッ' => 'ッ',
+ 'ー' => 'ー',
+ 'ア' => 'ア',
+ 'イ' => 'イ',
+ 'ウ' => 'ウ',
+ 'エ' => 'エ',
+ 'オ' => 'オ',
+ 'カ' => 'カ',
+ 'キ' => 'キ',
+ 'ク' => 'ク',
+ 'ケ' => 'ケ',
+ 'コ' => 'コ',
+ 'サ' => 'サ',
+ 'シ' => 'シ',
+ 'ス' => 'ス',
+ 'セ' => 'セ',
+ 'ソ' => 'ソ',
+ 'タ' => 'タ',
+ 'チ' => 'チ',
+ 'ツ' => 'ツ',
+ 'テ' => 'テ',
+ 'ト' => 'ト',
+ 'ナ' => 'ナ',
+ 'ニ' => 'ニ',
+ 'ヌ' => 'ヌ',
+ 'ネ' => 'ネ',
+ 'ノ' => 'ノ',
+ 'ハ' => 'ハ',
+ 'ヒ' => 'ヒ',
+ 'フ' => 'フ',
+ 'ヘ' => 'ヘ',
+ 'ホ' => 'ホ',
+ 'マ' => 'マ',
+ 'ミ' => 'ミ',
+ 'ム' => 'ム',
+ 'メ' => 'メ',
+ 'モ' => 'モ',
+ 'ヤ' => 'ヤ',
+ 'ユ' => 'ユ',
+ 'ヨ' => 'ヨ',
+ 'ラ' => 'ラ',
+ 'リ' => 'リ',
+ 'ル' => 'ル',
+ 'レ' => 'レ',
+ 'ロ' => 'ロ',
+ 'ワ' => 'ワ',
+ 'ン' => 'ン',
+ '゙' => '゙',
+ '゚' => '゚',
+ 'ᅠ' => 'ᅠ',
+ 'ᄀ' => 'ᄀ',
+ 'ᄁ' => 'ᄁ',
+ 'ᆪ' => 'ᆪ',
+ 'ᄂ' => 'ᄂ',
+ 'ᆬ' => 'ᆬ',
+ 'ᆭ' => 'ᆭ',
+ 'ᄃ' => 'ᄃ',
+ 'ᄄ' => 'ᄄ',
+ 'ᄅ' => 'ᄅ',
+ 'ᆰ' => 'ᆰ',
+ 'ᆱ' => 'ᆱ',
+ 'ᆲ' => 'ᆲ',
+ 'ᆳ' => 'ᆳ',
+ 'ᆴ' => 'ᆴ',
+ 'ᆵ' => 'ᆵ',
+ 'ᄚ' => 'ᄚ',
+ 'ᄆ' => 'ᄆ',
+ 'ᄇ' => 'ᄇ',
+ 'ᄈ' => 'ᄈ',
+ 'ᄡ' => 'ᄡ',
+ 'ᄉ' => 'ᄉ',
+ 'ᄊ' => 'ᄊ',
+ 'ᄋ' => 'ᄋ',
+ 'ᄌ' => 'ᄌ',
+ 'ᄍ' => 'ᄍ',
+ 'ᄎ' => 'ᄎ',
+ 'ᄏ' => 'ᄏ',
+ 'ᄐ' => 'ᄐ',
+ 'ᄑ' => 'ᄑ',
+ 'ᄒ' => 'ᄒ',
+ 'ᅡ' => 'ᅡ',
+ 'ᅢ' => 'ᅢ',
+ 'ᅣ' => 'ᅣ',
+ 'ᅤ' => 'ᅤ',
+ 'ᅥ' => 'ᅥ',
+ 'ᅦ' => 'ᅦ',
+ 'ᅧ' => 'ᅧ',
+ 'ᅨ' => 'ᅨ',
+ 'ᅩ' => 'ᅩ',
+ 'ᅪ' => 'ᅪ',
+ 'ᅫ' => 'ᅫ',
+ 'ᅬ' => 'ᅬ',
+ 'ᅭ' => 'ᅭ',
+ 'ᅮ' => 'ᅮ',
+ 'ᅯ' => 'ᅯ',
+ 'ᅰ' => 'ᅰ',
+ 'ᅱ' => 'ᅱ',
+ 'ᅲ' => 'ᅲ',
+ 'ᅳ' => 'ᅳ',
+ 'ᅴ' => 'ᅴ',
+ 'ᅵ' => 'ᅵ',
+ '¢' => '¢',
+ '£' => '£',
+ '¬' => '¬',
+ ' ̄' => ' ̄',
+ '¦' => '¦',
+ '¥' => '¥',
+ '₩' => '₩',
+ '│' => '│',
+ '←' => '←',
+ '↑' => '↑',
+ '→' => '→',
+ '↓' => '↓',
+ '■' => '■',
+ '○' => '○',
+ '𝐀' => 'A',
+ '𝐁' => 'B',
+ '𝐂' => 'C',
+ '𝐃' => 'D',
+ '𝐄' => 'E',
+ '𝐅' => 'F',
+ '𝐆' => 'G',
+ '𝐇' => 'H',
+ '𝐈' => 'I',
+ '𝐉' => 'J',
+ '𝐊' => 'K',
+ '𝐋' => 'L',
+ '𝐌' => 'M',
+ '𝐍' => 'N',
+ '𝐎' => 'O',
+ '𝐏' => 'P',
+ '𝐐' => 'Q',
+ '𝐑' => 'R',
+ '𝐒' => 'S',
+ '𝐓' => 'T',
+ '𝐔' => 'U',
+ '𝐕' => 'V',
+ '𝐖' => 'W',
+ '𝐗' => 'X',
+ '𝐘' => 'Y',
+ '𝐙' => 'Z',
+ '𝐚' => 'a',
+ '𝐛' => 'b',
+ '𝐜' => 'c',
+ '𝐝' => 'd',
+ '𝐞' => 'e',
+ '𝐟' => 'f',
+ '𝐠' => 'g',
+ '𝐡' => 'h',
+ '𝐢' => 'i',
+ '𝐣' => 'j',
+ '𝐤' => 'k',
+ '𝐥' => 'l',
+ '𝐦' => 'm',
+ '𝐧' => 'n',
+ '𝐨' => 'o',
+ '𝐩' => 'p',
+ '𝐪' => 'q',
+ '𝐫' => 'r',
+ '𝐬' => 's',
+ '𝐭' => 't',
+ '𝐮' => 'u',
+ '𝐯' => 'v',
+ '𝐰' => 'w',
+ '𝐱' => 'x',
+ '𝐲' => 'y',
+ '𝐳' => 'z',
+ '𝐴' => 'A',
+ '𝐵' => 'B',
+ '𝐶' => 'C',
+ '𝐷' => 'D',
+ '𝐸' => 'E',
+ '𝐹' => 'F',
+ '𝐺' => 'G',
+ '𝐻' => 'H',
+ '𝐼' => 'I',
+ '𝐽' => 'J',
+ '𝐾' => 'K',
+ '𝐿' => 'L',
+ '𝑀' => 'M',
+ '𝑁' => 'N',
+ '𝑂' => 'O',
+ '𝑃' => 'P',
+ '𝑄' => 'Q',
+ '𝑅' => 'R',
+ '𝑆' => 'S',
+ '𝑇' => 'T',
+ '𝑈' => 'U',
+ '𝑉' => 'V',
+ '𝑊' => 'W',
+ '𝑋' => 'X',
+ '𝑌' => 'Y',
+ '𝑍' => 'Z',
+ '𝑎' => 'a',
+ '𝑏' => 'b',
+ '𝑐' => 'c',
+ '𝑑' => 'd',
+ '𝑒' => 'e',
+ '𝑓' => 'f',
+ '𝑔' => 'g',
+ '𝑖' => 'i',
+ '𝑗' => 'j',
+ '𝑘' => 'k',
+ '𝑙' => 'l',
+ '𝑚' => 'm',
+ '𝑛' => 'n',
+ '𝑜' => 'o',
+ '𝑝' => 'p',
+ '𝑞' => 'q',
+ '𝑟' => 'r',
+ '𝑠' => 's',
+ '𝑡' => 't',
+ '𝑢' => 'u',
+ '𝑣' => 'v',
+ '𝑤' => 'w',
+ '𝑥' => 'x',
+ '𝑦' => 'y',
+ '𝑧' => 'z',
+ '𝑨' => 'A',
+ '𝑩' => 'B',
+ '𝑪' => 'C',
+ '𝑫' => 'D',
+ '𝑬' => 'E',
+ '𝑭' => 'F',
+ '𝑮' => 'G',
+ '𝑯' => 'H',
+ '𝑰' => 'I',
+ '𝑱' => 'J',
+ '𝑲' => 'K',
+ '𝑳' => 'L',
+ '𝑴' => 'M',
+ '𝑵' => 'N',
+ '𝑶' => 'O',
+ '𝑷' => 'P',
+ '𝑸' => 'Q',
+ '𝑹' => 'R',
+ '𝑺' => 'S',
+ '𝑻' => 'T',
+ '𝑼' => 'U',
+ '𝑽' => 'V',
+ '𝑾' => 'W',
+ '𝑿' => 'X',
+ '𝒀' => 'Y',
+ '𝒁' => 'Z',
+ '𝒂' => 'a',
+ '𝒃' => 'b',
+ '𝒄' => 'c',
+ '𝒅' => 'd',
+ '𝒆' => 'e',
+ '𝒇' => 'f',
+ '𝒈' => 'g',
+ '𝒉' => 'h',
+ '𝒊' => 'i',
+ '𝒋' => 'j',
+ '𝒌' => 'k',
+ '𝒍' => 'l',
+ '𝒎' => 'm',
+ '𝒏' => 'n',
+ '𝒐' => 'o',
+ '𝒑' => 'p',
+ '𝒒' => 'q',
+ '𝒓' => 'r',
+ '𝒔' => 's',
+ '𝒕' => 't',
+ '𝒖' => 'u',
+ '𝒗' => 'v',
+ '𝒘' => 'w',
+ '𝒙' => 'x',
+ '𝒚' => 'y',
+ '𝒛' => 'z',
+ '𝒜' => 'A',
+ '𝒞' => 'C',
+ '𝒟' => 'D',
+ '𝒢' => 'G',
+ '𝒥' => 'J',
+ '𝒦' => 'K',
+ '𝒩' => 'N',
+ '𝒪' => 'O',
+ '𝒫' => 'P',
+ '𝒬' => 'Q',
+ '𝒮' => 'S',
+ '𝒯' => 'T',
+ '𝒰' => 'U',
+ '𝒱' => 'V',
+ '𝒲' => 'W',
+ '𝒳' => 'X',
+ '𝒴' => 'Y',
+ '𝒵' => 'Z',
+ '𝒶' => 'a',
+ '𝒷' => 'b',
+ '𝒸' => 'c',
+ '𝒹' => 'd',
+ '𝒻' => 'f',
+ '𝒽' => 'h',
+ '𝒾' => 'i',
+ '𝒿' => 'j',
+ '𝓀' => 'k',
+ '𝓁' => 'l',
+ '𝓂' => 'm',
+ '𝓃' => 'n',
+ '𝓅' => 'p',
+ '𝓆' => 'q',
+ '𝓇' => 'r',
+ '𝓈' => 's',
+ '𝓉' => 't',
+ '𝓊' => 'u',
+ '𝓋' => 'v',
+ '𝓌' => 'w',
+ '𝓍' => 'x',
+ '𝓎' => 'y',
+ '𝓏' => 'z',
+ '𝓐' => 'A',
+ '𝓑' => 'B',
+ '𝓒' => 'C',
+ '𝓓' => 'D',
+ '𝓔' => 'E',
+ '𝓕' => 'F',
+ '𝓖' => 'G',
+ '𝓗' => 'H',
+ '𝓘' => 'I',
+ '𝓙' => 'J',
+ '𝓚' => 'K',
+ '𝓛' => 'L',
+ '𝓜' => 'M',
+ '𝓝' => 'N',
+ '𝓞' => 'O',
+ '𝓟' => 'P',
+ '𝓠' => 'Q',
+ '𝓡' => 'R',
+ '𝓢' => 'S',
+ '𝓣' => 'T',
+ '𝓤' => 'U',
+ '𝓥' => 'V',
+ '𝓦' => 'W',
+ '𝓧' => 'X',
+ '𝓨' => 'Y',
+ '𝓩' => 'Z',
+ '𝓪' => 'a',
+ '𝓫' => 'b',
+ '𝓬' => 'c',
+ '𝓭' => 'd',
+ '𝓮' => 'e',
+ '𝓯' => 'f',
+ '𝓰' => 'g',
+ '𝓱' => 'h',
+ '𝓲' => 'i',
+ '𝓳' => 'j',
+ '𝓴' => 'k',
+ '𝓵' => 'l',
+ '𝓶' => 'm',
+ '𝓷' => 'n',
+ '𝓸' => 'o',
+ '𝓹' => 'p',
+ '𝓺' => 'q',
+ '𝓻' => 'r',
+ '𝓼' => 's',
+ '𝓽' => 't',
+ '𝓾' => 'u',
+ '𝓿' => 'v',
+ '𝔀' => 'w',
+ '𝔁' => 'x',
+ '𝔂' => 'y',
+ '𝔃' => 'z',
+ '𝔄' => 'A',
+ '𝔅' => 'B',
+ '𝔇' => 'D',
+ '𝔈' => 'E',
+ '𝔉' => 'F',
+ '𝔊' => 'G',
+ '𝔍' => 'J',
+ '𝔎' => 'K',
+ '𝔏' => 'L',
+ '𝔐' => 'M',
+ '𝔑' => 'N',
+ '𝔒' => 'O',
+ '𝔓' => 'P',
+ '𝔔' => 'Q',
+ '𝔖' => 'S',
+ '𝔗' => 'T',
+ '𝔘' => 'U',
+ '𝔙' => 'V',
+ '𝔚' => 'W',
+ '𝔛' => 'X',
+ '𝔜' => 'Y',
+ '𝔞' => 'a',
+ '𝔟' => 'b',
+ '𝔠' => 'c',
+ '𝔡' => 'd',
+ '𝔢' => 'e',
+ '𝔣' => 'f',
+ '𝔤' => 'g',
+ '𝔥' => 'h',
+ '𝔦' => 'i',
+ '𝔧' => 'j',
+ '𝔨' => 'k',
+ '𝔩' => 'l',
+ '𝔪' => 'm',
+ '𝔫' => 'n',
+ '𝔬' => 'o',
+ '𝔭' => 'p',
+ '𝔮' => 'q',
+ '𝔯' => 'r',
+ '𝔰' => 's',
+ '𝔱' => 't',
+ '𝔲' => 'u',
+ '𝔳' => 'v',
+ '𝔴' => 'w',
+ '𝔵' => 'x',
+ '𝔶' => 'y',
+ '𝔷' => 'z',
+ '𝔸' => 'A',
+ '𝔹' => 'B',
+ '𝔻' => 'D',
+ '𝔼' => 'E',
+ '𝔽' => 'F',
+ '𝔾' => 'G',
+ '𝕀' => 'I',
+ '𝕁' => 'J',
+ '𝕂' => 'K',
+ '𝕃' => 'L',
+ '𝕄' => 'M',
+ '𝕆' => 'O',
+ '𝕊' => 'S',
+ '𝕋' => 'T',
+ '𝕌' => 'U',
+ '𝕍' => 'V',
+ '𝕎' => 'W',
+ '𝕏' => 'X',
+ '𝕐' => 'Y',
+ '𝕒' => 'a',
+ '𝕓' => 'b',
+ '𝕔' => 'c',
+ '𝕕' => 'd',
+ '𝕖' => 'e',
+ '𝕗' => 'f',
+ '𝕘' => 'g',
+ '𝕙' => 'h',
+ '𝕚' => 'i',
+ '𝕛' => 'j',
+ '𝕜' => 'k',
+ '𝕝' => 'l',
+ '𝕞' => 'm',
+ '𝕟' => 'n',
+ '𝕠' => 'o',
+ '𝕡' => 'p',
+ '𝕢' => 'q',
+ '𝕣' => 'r',
+ '𝕤' => 's',
+ '𝕥' => 't',
+ '𝕦' => 'u',
+ '𝕧' => 'v',
+ '𝕨' => 'w',
+ '𝕩' => 'x',
+ '𝕪' => 'y',
+ '𝕫' => 'z',
+ '𝕬' => 'A',
+ '𝕭' => 'B',
+ '𝕮' => 'C',
+ '𝕯' => 'D',
+ '𝕰' => 'E',
+ '𝕱' => 'F',
+ '𝕲' => 'G',
+ '𝕳' => 'H',
+ '𝕴' => 'I',
+ '𝕵' => 'J',
+ '𝕶' => 'K',
+ '𝕷' => 'L',
+ '𝕸' => 'M',
+ '𝕹' => 'N',
+ '𝕺' => 'O',
+ '𝕻' => 'P',
+ '𝕼' => 'Q',
+ '𝕽' => 'R',
+ '𝕾' => 'S',
+ '𝕿' => 'T',
+ '𝖀' => 'U',
+ '𝖁' => 'V',
+ '𝖂' => 'W',
+ '𝖃' => 'X',
+ '𝖄' => 'Y',
+ '𝖅' => 'Z',
+ '𝖆' => 'a',
+ '𝖇' => 'b',
+ '𝖈' => 'c',
+ '𝖉' => 'd',
+ '𝖊' => 'e',
+ '𝖋' => 'f',
+ '𝖌' => 'g',
+ '𝖍' => 'h',
+ '𝖎' => 'i',
+ '𝖏' => 'j',
+ '𝖐' => 'k',
+ '𝖑' => 'l',
+ '𝖒' => 'm',
+ '𝖓' => 'n',
+ '𝖔' => 'o',
+ '𝖕' => 'p',
+ '𝖖' => 'q',
+ '𝖗' => 'r',
+ '𝖘' => 's',
+ '𝖙' => 't',
+ '𝖚' => 'u',
+ '𝖛' => 'v',
+ '𝖜' => 'w',
+ '𝖝' => 'x',
+ '𝖞' => 'y',
+ '𝖟' => 'z',
+ '𝖠' => 'A',
+ '𝖡' => 'B',
+ '𝖢' => 'C',
+ '𝖣' => 'D',
+ '𝖤' => 'E',
+ '𝖥' => 'F',
+ '𝖦' => 'G',
+ '𝖧' => 'H',
+ '𝖨' => 'I',
+ '𝖩' => 'J',
+ '𝖪' => 'K',
+ '𝖫' => 'L',
+ '𝖬' => 'M',
+ '𝖭' => 'N',
+ '𝖮' => 'O',
+ '𝖯' => 'P',
+ '𝖰' => 'Q',
+ '𝖱' => 'R',
+ '𝖲' => 'S',
+ '𝖳' => 'T',
+ '𝖴' => 'U',
+ '𝖵' => 'V',
+ '𝖶' => 'W',
+ '𝖷' => 'X',
+ '𝖸' => 'Y',
+ '𝖹' => 'Z',
+ '𝖺' => 'a',
+ '𝖻' => 'b',
+ '𝖼' => 'c',
+ '𝖽' => 'd',
+ '𝖾' => 'e',
+ '𝖿' => 'f',
+ '𝗀' => 'g',
+ '𝗁' => 'h',
+ '𝗂' => 'i',
+ '𝗃' => 'j',
+ '𝗄' => 'k',
+ '𝗅' => 'l',
+ '𝗆' => 'm',
+ '𝗇' => 'n',
+ '𝗈' => 'o',
+ '𝗉' => 'p',
+ '𝗊' => 'q',
+ '𝗋' => 'r',
+ '𝗌' => 's',
+ '𝗍' => 't',
+ '𝗎' => 'u',
+ '𝗏' => 'v',
+ '𝗐' => 'w',
+ '𝗑' => 'x',
+ '𝗒' => 'y',
+ '𝗓' => 'z',
+ '𝗔' => 'A',
+ '𝗕' => 'B',
+ '𝗖' => 'C',
+ '𝗗' => 'D',
+ '𝗘' => 'E',
+ '𝗙' => 'F',
+ '𝗚' => 'G',
+ '𝗛' => 'H',
+ '𝗜' => 'I',
+ '𝗝' => 'J',
+ '𝗞' => 'K',
+ '𝗟' => 'L',
+ '𝗠' => 'M',
+ '𝗡' => 'N',
+ '𝗢' => 'O',
+ '𝗣' => 'P',
+ '𝗤' => 'Q',
+ '𝗥' => 'R',
+ '𝗦' => 'S',
+ '𝗧' => 'T',
+ '𝗨' => 'U',
+ '𝗩' => 'V',
+ '𝗪' => 'W',
+ '𝗫' => 'X',
+ '𝗬' => 'Y',
+ '𝗭' => 'Z',
+ '𝗮' => 'a',
+ '𝗯' => 'b',
+ '𝗰' => 'c',
+ '𝗱' => 'd',
+ '𝗲' => 'e',
+ '𝗳' => 'f',
+ '𝗴' => 'g',
+ '𝗵' => 'h',
+ '𝗶' => 'i',
+ '𝗷' => 'j',
+ '𝗸' => 'k',
+ '𝗹' => 'l',
+ '𝗺' => 'm',
+ '𝗻' => 'n',
+ '𝗼' => 'o',
+ '𝗽' => 'p',
+ '𝗾' => 'q',
+ '𝗿' => 'r',
+ '𝘀' => 's',
+ '𝘁' => 't',
+ '𝘂' => 'u',
+ '𝘃' => 'v',
+ '𝘄' => 'w',
+ '𝘅' => 'x',
+ '𝘆' => 'y',
+ '𝘇' => 'z',
+ '𝘈' => 'A',
+ '𝘉' => 'B',
+ '𝘊' => 'C',
+ '𝘋' => 'D',
+ '𝘌' => 'E',
+ '𝘍' => 'F',
+ '𝘎' => 'G',
+ '𝘏' => 'H',
+ '𝘐' => 'I',
+ '𝘑' => 'J',
+ '𝘒' => 'K',
+ '𝘓' => 'L',
+ '𝘔' => 'M',
+ '𝘕' => 'N',
+ '𝘖' => 'O',
+ '𝘗' => 'P',
+ '𝘘' => 'Q',
+ '𝘙' => 'R',
+ '𝘚' => 'S',
+ '𝘛' => 'T',
+ '𝘜' => 'U',
+ '𝘝' => 'V',
+ '𝘞' => 'W',
+ '𝘟' => 'X',
+ '𝘠' => 'Y',
+ '𝘡' => 'Z',
+ '𝘢' => 'a',
+ '𝘣' => 'b',
+ '𝘤' => 'c',
+ '𝘥' => 'd',
+ '𝘦' => 'e',
+ '𝘧' => 'f',
+ '𝘨' => 'g',
+ '𝘩' => 'h',
+ '𝘪' => 'i',
+ '𝘫' => 'j',
+ '𝘬' => 'k',
+ '𝘭' => 'l',
+ '𝘮' => 'm',
+ '𝘯' => 'n',
+ '𝘰' => 'o',
+ '𝘱' => 'p',
+ '𝘲' => 'q',
+ '𝘳' => 'r',
+ '𝘴' => 's',
+ '𝘵' => 't',
+ '𝘶' => 'u',
+ '𝘷' => 'v',
+ '𝘸' => 'w',
+ '𝘹' => 'x',
+ '𝘺' => 'y',
+ '𝘻' => 'z',
+ '𝘼' => 'A',
+ '𝘽' => 'B',
+ '𝘾' => 'C',
+ '𝘿' => 'D',
+ '𝙀' => 'E',
+ '𝙁' => 'F',
+ '𝙂' => 'G',
+ '𝙃' => 'H',
+ '𝙄' => 'I',
+ '𝙅' => 'J',
+ '𝙆' => 'K',
+ '𝙇' => 'L',
+ '𝙈' => 'M',
+ '𝙉' => 'N',
+ '𝙊' => 'O',
+ '𝙋' => 'P',
+ '𝙌' => 'Q',
+ '𝙍' => 'R',
+ '𝙎' => 'S',
+ '𝙏' => 'T',
+ '𝙐' => 'U',
+ '𝙑' => 'V',
+ '𝙒' => 'W',
+ '𝙓' => 'X',
+ '𝙔' => 'Y',
+ '𝙕' => 'Z',
+ '𝙖' => 'a',
+ '𝙗' => 'b',
+ '𝙘' => 'c',
+ '𝙙' => 'd',
+ '𝙚' => 'e',
+ '𝙛' => 'f',
+ '𝙜' => 'g',
+ '𝙝' => 'h',
+ '𝙞' => 'i',
+ '𝙟' => 'j',
+ '𝙠' => 'k',
+ '𝙡' => 'l',
+ '𝙢' => 'm',
+ '𝙣' => 'n',
+ '𝙤' => 'o',
+ '𝙥' => 'p',
+ '𝙦' => 'q',
+ '𝙧' => 'r',
+ '𝙨' => 's',
+ '𝙩' => 't',
+ '𝙪' => 'u',
+ '𝙫' => 'v',
+ '𝙬' => 'w',
+ '𝙭' => 'x',
+ '𝙮' => 'y',
+ '𝙯' => 'z',
+ '𝙰' => 'A',
+ '𝙱' => 'B',
+ '𝙲' => 'C',
+ '𝙳' => 'D',
+ '𝙴' => 'E',
+ '𝙵' => 'F',
+ '𝙶' => 'G',
+ '𝙷' => 'H',
+ '𝙸' => 'I',
+ '𝙹' => 'J',
+ '𝙺' => 'K',
+ '𝙻' => 'L',
+ '𝙼' => 'M',
+ '𝙽' => 'N',
+ '𝙾' => 'O',
+ '𝙿' => 'P',
+ '𝚀' => 'Q',
+ '𝚁' => 'R',
+ '𝚂' => 'S',
+ '𝚃' => 'T',
+ '𝚄' => 'U',
+ '𝚅' => 'V',
+ '𝚆' => 'W',
+ '𝚇' => 'X',
+ '𝚈' => 'Y',
+ '𝚉' => 'Z',
+ '𝚊' => 'a',
+ '𝚋' => 'b',
+ '𝚌' => 'c',
+ '𝚍' => 'd',
+ '𝚎' => 'e',
+ '𝚏' => 'f',
+ '𝚐' => 'g',
+ '𝚑' => 'h',
+ '𝚒' => 'i',
+ '𝚓' => 'j',
+ '𝚔' => 'k',
+ '𝚕' => 'l',
+ '𝚖' => 'm',
+ '𝚗' => 'n',
+ '𝚘' => 'o',
+ '𝚙' => 'p',
+ '𝚚' => 'q',
+ '𝚛' => 'r',
+ '𝚜' => 's',
+ '𝚝' => 't',
+ '𝚞' => 'u',
+ '𝚟' => 'v',
+ '𝚠' => 'w',
+ '𝚡' => 'x',
+ '𝚢' => 'y',
+ '𝚣' => 'z',
+ '𝚤' => 'ı',
+ '𝚥' => 'ȷ',
+ '𝚨' => 'Α',
+ '𝚩' => 'Β',
+ '𝚪' => 'Γ',
+ '𝚫' => 'Δ',
+ '𝚬' => 'Ε',
+ '𝚭' => 'Ζ',
+ '𝚮' => 'Η',
+ '𝚯' => 'Θ',
+ '𝚰' => 'Ι',
+ '𝚱' => 'Κ',
+ '𝚲' => 'Λ',
+ '𝚳' => 'Μ',
+ '𝚴' => 'Ν',
+ '𝚵' => 'Ξ',
+ '𝚶' => 'Ο',
+ '𝚷' => 'Π',
+ '𝚸' => 'Ρ',
+ '𝚹' => 'Θ',
+ '𝚺' => 'Σ',
+ '𝚻' => 'Τ',
+ '𝚼' => 'Υ',
+ '𝚽' => 'Φ',
+ '𝚾' => 'Χ',
+ '𝚿' => 'Ψ',
+ '𝛀' => 'Ω',
+ '𝛁' => '∇',
+ '𝛂' => 'α',
+ '𝛃' => 'β',
+ '𝛄' => 'γ',
+ '𝛅' => 'δ',
+ '𝛆' => 'ε',
+ '𝛇' => 'ζ',
+ '𝛈' => 'η',
+ '𝛉' => 'θ',
+ '𝛊' => 'ι',
+ '𝛋' => 'κ',
+ '𝛌' => 'λ',
+ '𝛍' => 'μ',
+ '𝛎' => 'ν',
+ '𝛏' => 'ξ',
+ '𝛐' => 'ο',
+ '𝛑' => 'π',
+ '𝛒' => 'ρ',
+ '𝛓' => 'ς',
+ '𝛔' => 'σ',
+ '𝛕' => 'τ',
+ '𝛖' => 'υ',
+ '𝛗' => 'φ',
+ '𝛘' => 'χ',
+ '𝛙' => 'ψ',
+ '𝛚' => 'ω',
+ '𝛛' => '∂',
+ '𝛜' => 'ε',
+ '𝛝' => 'θ',
+ '𝛞' => 'κ',
+ '𝛟' => 'φ',
+ '𝛠' => 'ρ',
+ '𝛡' => 'π',
+ '𝛢' => 'Α',
+ '𝛣' => 'Β',
+ '𝛤' => 'Γ',
+ '𝛥' => 'Δ',
+ '𝛦' => 'Ε',
+ '𝛧' => 'Ζ',
+ '𝛨' => 'Η',
+ '𝛩' => 'Θ',
+ '𝛪' => 'Ι',
+ '𝛫' => 'Κ',
+ '𝛬' => 'Λ',
+ '𝛭' => 'Μ',
+ '𝛮' => 'Ν',
+ '𝛯' => 'Ξ',
+ '𝛰' => 'Ο',
+ '𝛱' => 'Π',
+ '𝛲' => 'Ρ',
+ '𝛳' => 'Θ',
+ '𝛴' => 'Σ',
+ '𝛵' => 'Τ',
+ '𝛶' => 'Υ',
+ '𝛷' => 'Φ',
+ '𝛸' => 'Χ',
+ '𝛹' => 'Ψ',
+ '𝛺' => 'Ω',
+ '𝛻' => '∇',
+ '𝛼' => 'α',
+ '𝛽' => 'β',
+ '𝛾' => 'γ',
+ '𝛿' => 'δ',
+ '𝜀' => 'ε',
+ '𝜁' => 'ζ',
+ '𝜂' => 'η',
+ '𝜃' => 'θ',
+ '𝜄' => 'ι',
+ '𝜅' => 'κ',
+ '𝜆' => 'λ',
+ '𝜇' => 'μ',
+ '𝜈' => 'ν',
+ '𝜉' => 'ξ',
+ '𝜊' => 'ο',
+ '𝜋' => 'π',
+ '𝜌' => 'ρ',
+ '𝜍' => 'ς',
+ '𝜎' => 'σ',
+ '𝜏' => 'τ',
+ '𝜐' => 'υ',
+ '𝜑' => 'φ',
+ '𝜒' => 'χ',
+ '𝜓' => 'ψ',
+ '𝜔' => 'ω',
+ '𝜕' => '∂',
+ '𝜖' => 'ε',
+ '𝜗' => 'θ',
+ '𝜘' => 'κ',
+ '𝜙' => 'φ',
+ '𝜚' => 'ρ',
+ '𝜛' => 'π',
+ '𝜜' => 'Α',
+ '𝜝' => 'Β',
+ '𝜞' => 'Γ',
+ '𝜟' => 'Δ',
+ '𝜠' => 'Ε',
+ '𝜡' => 'Ζ',
+ '𝜢' => 'Η',
+ '𝜣' => 'Θ',
+ '𝜤' => 'Ι',
+ '𝜥' => 'Κ',
+ '𝜦' => 'Λ',
+ '𝜧' => 'Μ',
+ '𝜨' => 'Ν',
+ '𝜩' => 'Ξ',
+ '𝜪' => 'Ο',
+ '𝜫' => 'Π',
+ '𝜬' => 'Ρ',
+ '𝜭' => 'Θ',
+ '𝜮' => 'Σ',
+ '𝜯' => 'Τ',
+ '𝜰' => 'Υ',
+ '𝜱' => 'Φ',
+ '𝜲' => 'Χ',
+ '𝜳' => 'Ψ',
+ '𝜴' => 'Ω',
+ '𝜵' => '∇',
+ '𝜶' => 'α',
+ '𝜷' => 'β',
+ '𝜸' => 'γ',
+ '𝜹' => 'δ',
+ '𝜺' => 'ε',
+ '𝜻' => 'ζ',
+ '𝜼' => 'η',
+ '𝜽' => 'θ',
+ '𝜾' => 'ι',
+ '𝜿' => 'κ',
+ '𝝀' => 'λ',
+ '𝝁' => 'μ',
+ '𝝂' => 'ν',
+ '𝝃' => 'ξ',
+ '𝝄' => 'ο',
+ '𝝅' => 'π',
+ '𝝆' => 'ρ',
+ '𝝇' => 'ς',
+ '𝝈' => 'σ',
+ '𝝉' => 'τ',
+ '𝝊' => 'υ',
+ '𝝋' => 'φ',
+ '𝝌' => 'χ',
+ '𝝍' => 'ψ',
+ '𝝎' => 'ω',
+ '𝝏' => '∂',
+ '𝝐' => 'ε',
+ '𝝑' => 'θ',
+ '𝝒' => 'κ',
+ '𝝓' => 'φ',
+ '𝝔' => 'ρ',
+ '𝝕' => 'π',
+ '𝝖' => 'Α',
+ '𝝗' => 'Β',
+ '𝝘' => 'Γ',
+ '𝝙' => 'Δ',
+ '𝝚' => 'Ε',
+ '𝝛' => 'Ζ',
+ '𝝜' => 'Η',
+ '𝝝' => 'Θ',
+ '𝝞' => 'Ι',
+ '𝝟' => 'Κ',
+ '𝝠' => 'Λ',
+ '𝝡' => 'Μ',
+ '𝝢' => 'Ν',
+ '𝝣' => 'Ξ',
+ '𝝤' => 'Ο',
+ '𝝥' => 'Π',
+ '𝝦' => 'Ρ',
+ '𝝧' => 'Θ',
+ '𝝨' => 'Σ',
+ '𝝩' => 'Τ',
+ '𝝪' => 'Υ',
+ '𝝫' => 'Φ',
+ '𝝬' => 'Χ',
+ '𝝭' => 'Ψ',
+ '𝝮' => 'Ω',
+ '𝝯' => '∇',
+ '𝝰' => 'α',
+ '𝝱' => 'β',
+ '𝝲' => 'γ',
+ '𝝳' => 'δ',
+ '𝝴' => 'ε',
+ '𝝵' => 'ζ',
+ '𝝶' => 'η',
+ '𝝷' => 'θ',
+ '𝝸' => 'ι',
+ '𝝹' => 'κ',
+ '𝝺' => 'λ',
+ '𝝻' => 'μ',
+ '𝝼' => 'ν',
+ '𝝽' => 'ξ',
+ '𝝾' => 'ο',
+ '𝝿' => 'π',
+ '𝞀' => 'ρ',
+ '𝞁' => 'ς',
+ '𝞂' => 'σ',
+ '𝞃' => 'τ',
+ '𝞄' => 'υ',
+ '𝞅' => 'φ',
+ '𝞆' => 'χ',
+ '𝞇' => 'ψ',
+ '𝞈' => 'ω',
+ '𝞉' => '∂',
+ '𝞊' => 'ε',
+ '𝞋' => 'θ',
+ '𝞌' => 'κ',
+ '𝞍' => 'φ',
+ '𝞎' => 'ρ',
+ '𝞏' => 'π',
+ '𝞐' => 'Α',
+ '𝞑' => 'Β',
+ '𝞒' => 'Γ',
+ '𝞓' => 'Δ',
+ '𝞔' => 'Ε',
+ '𝞕' => 'Ζ',
+ '𝞖' => 'Η',
+ '𝞗' => 'Θ',
+ '𝞘' => 'Ι',
+ '𝞙' => 'Κ',
+ '𝞚' => 'Λ',
+ '𝞛' => 'Μ',
+ '𝞜' => 'Ν',
+ '𝞝' => 'Ξ',
+ '𝞞' => 'Ο',
+ '𝞟' => 'Π',
+ '𝞠' => 'Ρ',
+ '𝞡' => 'Θ',
+ '𝞢' => 'Σ',
+ '𝞣' => 'Τ',
+ '𝞤' => 'Υ',
+ '𝞥' => 'Φ',
+ '𝞦' => 'Χ',
+ '𝞧' => 'Ψ',
+ '𝞨' => 'Ω',
+ '𝞩' => '∇',
+ '𝞪' => 'α',
+ '𝞫' => 'β',
+ '𝞬' => 'γ',
+ '𝞭' => 'δ',
+ '𝞮' => 'ε',
+ '𝞯' => 'ζ',
+ '𝞰' => 'η',
+ '𝞱' => 'θ',
+ '𝞲' => 'ι',
+ '𝞳' => 'κ',
+ '𝞴' => 'λ',
+ '𝞵' => 'μ',
+ '𝞶' => 'ν',
+ '𝞷' => 'ξ',
+ '𝞸' => 'ο',
+ '𝞹' => 'π',
+ '𝞺' => 'ρ',
+ '𝞻' => 'ς',
+ '𝞼' => 'σ',
+ '𝞽' => 'τ',
+ '𝞾' => 'υ',
+ '𝞿' => 'φ',
+ '𝟀' => 'χ',
+ '𝟁' => 'ψ',
+ '𝟂' => 'ω',
+ '𝟃' => '∂',
+ '𝟄' => 'ε',
+ '𝟅' => 'θ',
+ '𝟆' => 'κ',
+ '𝟇' => 'φ',
+ '𝟈' => 'ρ',
+ '𝟉' => 'π',
+ '𝟊' => 'Ϝ',
+ '𝟋' => 'ϝ',
+ '𝟎' => '0',
+ '𝟏' => '1',
+ '𝟐' => '2',
+ '𝟑' => '3',
+ '𝟒' => '4',
+ '𝟓' => '5',
+ '𝟔' => '6',
+ '𝟕' => '7',
+ '𝟖' => '8',
+ '𝟗' => '9',
+ '𝟘' => '0',
+ '𝟙' => '1',
+ '𝟚' => '2',
+ '𝟛' => '3',
+ '𝟜' => '4',
+ '𝟝' => '5',
+ '𝟞' => '6',
+ '𝟟' => '7',
+ '𝟠' => '8',
+ '𝟡' => '9',
+ '𝟢' => '0',
+ '𝟣' => '1',
+ '𝟤' => '2',
+ '𝟥' => '3',
+ '𝟦' => '4',
+ '𝟧' => '5',
+ '𝟨' => '6',
+ '𝟩' => '7',
+ '𝟪' => '8',
+ '𝟫' => '9',
+ '𝟬' => '0',
+ '𝟭' => '1',
+ '𝟮' => '2',
+ '𝟯' => '3',
+ '𝟰' => '4',
+ '𝟱' => '5',
+ '𝟲' => '6',
+ '𝟳' => '7',
+ '𝟴' => '8',
+ '𝟵' => '9',
+ '𝟶' => '0',
+ '𝟷' => '1',
+ '𝟸' => '2',
+ '𝟹' => '3',
+ '𝟺' => '4',
+ '𝟻' => '5',
+ '𝟼' => '6',
+ '𝟽' => '7',
+ '𝟾' => '8',
+ '𝟿' => '9',
+ '𞸀' => 'ا',
+ '𞸁' => 'ب',
+ '𞸂' => 'ج',
+ '𞸃' => 'د',
+ '𞸅' => 'و',
+ '𞸆' => 'ز',
+ '𞸇' => 'ح',
+ '𞸈' => 'ط',
+ '𞸉' => 'ي',
+ '𞸊' => 'ك',
+ '𞸋' => 'ل',
+ '𞸌' => 'م',
+ '𞸍' => 'ن',
+ '𞸎' => 'س',
+ '𞸏' => 'ع',
+ '𞸐' => 'ف',
+ '𞸑' => 'ص',
+ '𞸒' => 'ق',
+ '𞸓' => 'ر',
+ '𞸔' => 'ش',
+ '𞸕' => 'ت',
+ '𞸖' => 'ث',
+ '𞸗' => 'خ',
+ '𞸘' => 'ذ',
+ '𞸙' => 'ض',
+ '𞸚' => 'ظ',
+ '𞸛' => 'غ',
+ '𞸜' => 'ٮ',
+ '𞸝' => 'ں',
+ '𞸞' => 'ڡ',
+ '𞸟' => 'ٯ',
+ '𞸡' => 'ب',
+ '𞸢' => 'ج',
+ '𞸤' => 'ه',
+ '𞸧' => 'ح',
+ '𞸩' => 'ي',
+ '𞸪' => 'ك',
+ '𞸫' => 'ل',
+ '𞸬' => 'م',
+ '𞸭' => 'ن',
+ '𞸮' => 'س',
+ '𞸯' => 'ع',
+ '𞸰' => 'ف',
+ '𞸱' => 'ص',
+ '𞸲' => 'ق',
+ '𞸴' => 'ش',
+ '𞸵' => 'ت',
+ '𞸶' => 'ث',
+ '𞸷' => 'خ',
+ '𞸹' => 'ض',
+ '𞸻' => 'غ',
+ '𞹂' => 'ج',
+ '𞹇' => 'ح',
+ '𞹉' => 'ي',
+ '𞹋' => 'ل',
+ '𞹍' => 'ن',
+ '𞹎' => 'س',
+ '𞹏' => 'ع',
+ '𞹑' => 'ص',
+ '𞹒' => 'ق',
+ '𞹔' => 'ش',
+ '𞹗' => 'خ',
+ '𞹙' => 'ض',
+ '𞹛' => 'غ',
+ '𞹝' => 'ں',
+ '𞹟' => 'ٯ',
+ '𞹡' => 'ب',
+ '𞹢' => 'ج',
+ '𞹤' => 'ه',
+ '𞹧' => 'ح',
+ '𞹨' => 'ط',
+ '𞹩' => 'ي',
+ '𞹪' => 'ك',
+ '𞹬' => 'م',
+ '𞹭' => 'ن',
+ '𞹮' => 'س',
+ '𞹯' => 'ع',
+ '𞹰' => 'ف',
+ '𞹱' => 'ص',
+ '𞹲' => 'ق',
+ '𞹴' => 'ش',
+ '𞹵' => 'ت',
+ '𞹶' => 'ث',
+ '𞹷' => 'خ',
+ '𞹹' => 'ض',
+ '𞹺' => 'ظ',
+ '𞹻' => 'غ',
+ '𞹼' => 'ٮ',
+ '𞹾' => 'ڡ',
+ '𞺀' => 'ا',
+ '𞺁' => 'ب',
+ '𞺂' => 'ج',
+ '𞺃' => 'د',
+ '𞺄' => 'ه',
+ '𞺅' => 'و',
+ '𞺆' => 'ز',
+ '𞺇' => 'ح',
+ '𞺈' => 'ط',
+ '𞺉' => 'ي',
+ '𞺋' => 'ل',
+ '𞺌' => 'م',
+ '𞺍' => 'ن',
+ '𞺎' => 'س',
+ '𞺏' => 'ع',
+ '𞺐' => 'ف',
+ '𞺑' => 'ص',
+ '𞺒' => 'ق',
+ '𞺓' => 'ر',
+ '𞺔' => 'ش',
+ '𞺕' => 'ت',
+ '𞺖' => 'ث',
+ '𞺗' => 'خ',
+ '𞺘' => 'ذ',
+ '𞺙' => 'ض',
+ '𞺚' => 'ظ',
+ '𞺛' => 'غ',
+ '𞺡' => 'ب',
+ '𞺢' => 'ج',
+ '𞺣' => 'د',
+ '𞺥' => 'و',
+ '𞺦' => 'ز',
+ '𞺧' => 'ح',
+ '𞺨' => 'ط',
+ '𞺩' => 'ي',
+ '𞺫' => 'ل',
+ '𞺬' => 'م',
+ '𞺭' => 'ن',
+ '𞺮' => 'س',
+ '𞺯' => 'ع',
+ '𞺰' => 'ف',
+ '𞺱' => 'ص',
+ '𞺲' => 'ق',
+ '𞺳' => 'ر',
+ '𞺴' => 'ش',
+ '𞺵' => 'ت',
+ '𞺶' => 'ث',
+ '𞺷' => 'خ',
+ '𞺸' => 'ذ',
+ '𞺹' => 'ض',
+ '𞺺' => 'ظ',
+ '𞺻' => 'غ',
+ '🄀' => '0.',
+ '🄁' => '0,',
+ '🄂' => '1,',
+ '🄃' => '2,',
+ '🄄' => '3,',
+ '🄅' => '4,',
+ '🄆' => '5,',
+ '🄇' => '6,',
+ '🄈' => '7,',
+ '🄉' => '8,',
+ '🄊' => '9,',
+ '🄐' => '(A)',
+ '🄑' => '(B)',
+ '🄒' => '(C)',
+ '🄓' => '(D)',
+ '🄔' => '(E)',
+ '🄕' => '(F)',
+ '🄖' => '(G)',
+ '🄗' => '(H)',
+ '🄘' => '(I)',
+ '🄙' => '(J)',
+ '🄚' => '(K)',
+ '🄛' => '(L)',
+ '🄜' => '(M)',
+ '🄝' => '(N)',
+ '🄞' => '(O)',
+ '🄟' => '(P)',
+ '🄠' => '(Q)',
+ '🄡' => '(R)',
+ '🄢' => '(S)',
+ '🄣' => '(T)',
+ '🄤' => '(U)',
+ '🄥' => '(V)',
+ '🄦' => '(W)',
+ '🄧' => '(X)',
+ '🄨' => '(Y)',
+ '🄩' => '(Z)',
+ '🄪' => '〔S〕',
+ '🄫' => 'C',
+ '🄬' => 'R',
+ '🄭' => 'CD',
+ '🄮' => 'WZ',
+ '🄰' => 'A',
+ '🄱' => 'B',
+ '🄲' => 'C',
+ '🄳' => 'D',
+ '🄴' => 'E',
+ '🄵' => 'F',
+ '🄶' => 'G',
+ '🄷' => 'H',
+ '🄸' => 'I',
+ '🄹' => 'J',
+ '🄺' => 'K',
+ '🄻' => 'L',
+ '🄼' => 'M',
+ '🄽' => 'N',
+ '🄾' => 'O',
+ '🄿' => 'P',
+ '🅀' => 'Q',
+ '🅁' => 'R',
+ '🅂' => 'S',
+ '🅃' => 'T',
+ '🅄' => 'U',
+ '🅅' => 'V',
+ '🅆' => 'W',
+ '🅇' => 'X',
+ '🅈' => 'Y',
+ '🅉' => 'Z',
+ '🅊' => 'HV',
+ '🅋' => 'MV',
+ '🅌' => 'SD',
+ '🅍' => 'SS',
+ '🅎' => 'PPV',
+ '🅏' => 'WC',
+ '🅪' => 'MC',
+ '🅫' => 'MD',
+ '🅬' => 'MR',
+ '🆐' => 'DJ',
+ '🈀' => 'ほか',
+ '🈁' => 'ココ',
+ '🈂' => 'サ',
+ '🈐' => '手',
+ '🈑' => '字',
+ '🈒' => '双',
+ '🈓' => 'デ',
+ '🈔' => '二',
+ '🈕' => '多',
+ '🈖' => '解',
+ '🈗' => '天',
+ '🈘' => '交',
+ '🈙' => '映',
+ '🈚' => '無',
+ '🈛' => '料',
+ '🈜' => '前',
+ '🈝' => '後',
+ '🈞' => '再',
+ '🈟' => '新',
+ '🈠' => '初',
+ '🈡' => '終',
+ '🈢' => '生',
+ '🈣' => '販',
+ '🈤' => '声',
+ '🈥' => '吹',
+ '🈦' => '演',
+ '🈧' => '投',
+ '🈨' => '捕',
+ '🈩' => '一',
+ '🈪' => '三',
+ '🈫' => '遊',
+ '🈬' => '左',
+ '🈭' => '中',
+ '🈮' => '右',
+ '🈯' => '指',
+ '🈰' => '走',
+ '🈱' => '打',
+ '🈲' => '禁',
+ '🈳' => '空',
+ '🈴' => '合',
+ '🈵' => '満',
+ '🈶' => '有',
+ '🈷' => '月',
+ '🈸' => '申',
+ '🈹' => '割',
+ '🈺' => '営',
+ '🈻' => '配',
+ '🉀' => '〔本〕',
+ '🉁' => '〔三〕',
+ '🉂' => '〔二〕',
+ '🉃' => '〔安〕',
+ '🉄' => '〔点〕',
+ '🉅' => '〔打〕',
+ '🉆' => '〔盗〕',
+ '🉇' => '〔勝〕',
+ '🉈' => '〔敗〕',
+ '🉐' => '得',
+ '🉑' => '可',
+ '🯰' => '0',
+ '🯱' => '1',
+ '🯲' => '2',
+ '🯳' => '3',
+ '🯴' => '4',
+ '🯵' => '5',
+ '🯶' => '6',
+ '🯷' => '7',
+ '🯸' => '8',
+ '🯹' => '9',
+);
diff --git a/vendor/symfony/polyfill-intl-normalizer/bootstrap.php b/vendor/symfony/polyfill-intl-normalizer/bootstrap.php
new file mode 100644
index 000000000..3608e5c05
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-normalizer/bootstrap.php
@@ -0,0 +1,23 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+use Symfony\Polyfill\Intl\Normalizer as p;
+
+if (\PHP_VERSION_ID >= 80000) {
+ return require __DIR__.'/bootstrap80.php';
+}
+
+if (!function_exists('normalizer_is_normalized')) {
+ function normalizer_is_normalized($string, $form = p\Normalizer::FORM_C) { return p\Normalizer::isNormalized($string, $form); }
+}
+if (!function_exists('normalizer_normalize')) {
+ function normalizer_normalize($string, $form = p\Normalizer::FORM_C) { return p\Normalizer::normalize($string, $form); }
+}
diff --git a/vendor/symfony/polyfill-intl-normalizer/bootstrap80.php b/vendor/symfony/polyfill-intl-normalizer/bootstrap80.php
new file mode 100644
index 000000000..e36d1a947
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-normalizer/bootstrap80.php
@@ -0,0 +1,19 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+use Symfony\Polyfill\Intl\Normalizer as p;
+
+if (!function_exists('normalizer_is_normalized')) {
+ function normalizer_is_normalized(?string $string, ?int $form = p\Normalizer::FORM_C): bool { return p\Normalizer::isNormalized((string) $string, (int) $form); }
+}
+if (!function_exists('normalizer_normalize')) {
+ function normalizer_normalize(?string $string, ?int $form = p\Normalizer::FORM_C): string|false { return p\Normalizer::normalize((string) $string, (int) $form); }
+}
diff --git a/vendor/symfony/polyfill-intl-normalizer/composer.json b/vendor/symfony/polyfill-intl-normalizer/composer.json
new file mode 100644
index 000000000..65f72d645
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-normalizer/composer.json
@@ -0,0 +1,39 @@
+{
+ "name": "symfony/polyfill-intl-normalizer",
+ "type": "library",
+ "description": "Symfony polyfill for intl's Normalizer class and related functions",
+ "keywords": ["polyfill", "shim", "compatibility", "portable", "intl", "normalizer"],
+ "homepage": "https://symfony.com",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=7.1"
+ },
+ "autoload": {
+ "psr-4": { "Symfony\\Polyfill\\Intl\\Normalizer\\": "" },
+ "files": [ "bootstrap.php" ],
+ "classmap": [ "Resources/stubs" ]
+ },
+ "suggest": {
+ "ext-intl": "For best performance"
+ },
+ "minimum-stability": "dev",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.27-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ }
+}
diff --git a/vendor/symfony/string/AbstractString.php b/vendor/symfony/string/AbstractString.php
new file mode 100644
index 000000000..13567c7b0
--- /dev/null
+++ b/vendor/symfony/string/AbstractString.php
@@ -0,0 +1,795 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\String;
+
+use Symfony\Component\String\Exception\ExceptionInterface;
+use Symfony\Component\String\Exception\InvalidArgumentException;
+use Symfony\Component\String\Exception\RuntimeException;
+
+/**
+ * Represents a string of abstract characters.
+ *
+ * Unicode defines 3 types of "characters" (bytes, code points and grapheme clusters).
+ * This class is the abstract type to use as a type-hint when the logic you want to
+ * implement doesn't care about the exact variant it deals with.
+ *
+ * @author Nicolas Grekas
+ * @author Hugo Hamon
+ *
+ * @throws ExceptionInterface
+ */
+abstract class AbstractString implements \Stringable, \JsonSerializable
+{
+ public const PREG_PATTERN_ORDER = \PREG_PATTERN_ORDER;
+ public const PREG_SET_ORDER = \PREG_SET_ORDER;
+ public const PREG_OFFSET_CAPTURE = \PREG_OFFSET_CAPTURE;
+ public const PREG_UNMATCHED_AS_NULL = \PREG_UNMATCHED_AS_NULL;
+
+ public const PREG_SPLIT = 0;
+ public const PREG_SPLIT_NO_EMPTY = \PREG_SPLIT_NO_EMPTY;
+ public const PREG_SPLIT_DELIM_CAPTURE = \PREG_SPLIT_DELIM_CAPTURE;
+ public const PREG_SPLIT_OFFSET_CAPTURE = \PREG_SPLIT_OFFSET_CAPTURE;
+
+ protected $string = '';
+ protected $ignoreCase = false;
+
+ abstract public function __construct(string $string = '');
+
+ /**
+ * Unwraps instances of AbstractString back to strings.
+ *
+ * @return string[]|array
+ */
+ public static function unwrap(array $values): array
+ {
+ foreach ($values as $k => $v) {
+ if ($v instanceof self) {
+ $values[$k] = $v->__toString();
+ } elseif (\is_array($v) && $values[$k] !== $v = static::unwrap($v)) {
+ $values[$k] = $v;
+ }
+ }
+
+ return $values;
+ }
+
+ /**
+ * Wraps (and normalizes) strings in instances of AbstractString.
+ *
+ * @return static[]|array
+ */
+ public static function wrap(array $values): array
+ {
+ $i = 0;
+ $keys = null;
+
+ foreach ($values as $k => $v) {
+ if (\is_string($k) && '' !== $k && $k !== $j = (string) new static($k)) {
+ $keys = $keys ?? array_keys($values);
+ $keys[$i] = $j;
+ }
+
+ if (\is_string($v)) {
+ $values[$k] = new static($v);
+ } elseif (\is_array($v) && $values[$k] !== $v = static::wrap($v)) {
+ $values[$k] = $v;
+ }
+
+ ++$i;
+ }
+
+ return null !== $keys ? array_combine($keys, $values) : $values;
+ }
+
+ /**
+ * @param string|string[] $needle
+ *
+ * @return static
+ */
+ public function after($needle, bool $includeNeedle = false, int $offset = 0): self
+ {
+ $str = clone $this;
+ $i = \PHP_INT_MAX;
+
+ foreach ((array) $needle as $n) {
+ $n = (string) $n;
+ $j = $this->indexOf($n, $offset);
+
+ if (null !== $j && $j < $i) {
+ $i = $j;
+ $str->string = $n;
+ }
+ }
+
+ if (\PHP_INT_MAX === $i) {
+ return $str;
+ }
+
+ if (!$includeNeedle) {
+ $i += $str->length();
+ }
+
+ return $this->slice($i);
+ }
+
+ /**
+ * @param string|string[] $needle
+ *
+ * @return static
+ */
+ public function afterLast($needle, bool $includeNeedle = false, int $offset = 0): self
+ {
+ $str = clone $this;
+ $i = null;
+
+ foreach ((array) $needle as $n) {
+ $n = (string) $n;
+ $j = $this->indexOfLast($n, $offset);
+
+ if (null !== $j && $j >= $i) {
+ $i = $offset = $j;
+ $str->string = $n;
+ }
+ }
+
+ if (null === $i) {
+ return $str;
+ }
+
+ if (!$includeNeedle) {
+ $i += $str->length();
+ }
+
+ return $this->slice($i);
+ }
+
+ /**
+ * @return static
+ */
+ abstract public function append(string ...$suffix): self;
+
+ /**
+ * @param string|string[] $needle
+ *
+ * @return static
+ */
+ public function before($needle, bool $includeNeedle = false, int $offset = 0): self
+ {
+ $str = clone $this;
+ $i = \PHP_INT_MAX;
+
+ foreach ((array) $needle as $n) {
+ $n = (string) $n;
+ $j = $this->indexOf($n, $offset);
+
+ if (null !== $j && $j < $i) {
+ $i = $j;
+ $str->string = $n;
+ }
+ }
+
+ if (\PHP_INT_MAX === $i) {
+ return $str;
+ }
+
+ if ($includeNeedle) {
+ $i += $str->length();
+ }
+
+ return $this->slice(0, $i);
+ }
+
+ /**
+ * @param string|string[] $needle
+ *
+ * @return static
+ */
+ public function beforeLast($needle, bool $includeNeedle = false, int $offset = 0): self
+ {
+ $str = clone $this;
+ $i = null;
+
+ foreach ((array) $needle as $n) {
+ $n = (string) $n;
+ $j = $this->indexOfLast($n, $offset);
+
+ if (null !== $j && $j >= $i) {
+ $i = $offset = $j;
+ $str->string = $n;
+ }
+ }
+
+ if (null === $i) {
+ return $str;
+ }
+
+ if ($includeNeedle) {
+ $i += $str->length();
+ }
+
+ return $this->slice(0, $i);
+ }
+
+ /**
+ * @return int[]
+ */
+ public function bytesAt(int $offset): array
+ {
+ $str = $this->slice($offset, 1);
+
+ return '' === $str->string ? [] : array_values(unpack('C*', $str->string));
+ }
+
+ /**
+ * @return static
+ */
+ abstract public function camel(): self;
+
+ /**
+ * @return static[]
+ */
+ abstract public function chunk(int $length = 1): array;
+
+ /**
+ * @return static
+ */
+ public function collapseWhitespace(): self
+ {
+ $str = clone $this;
+ $str->string = trim(preg_replace("/(?:[ \n\r\t\x0C]{2,}+|[\n\r\t\x0C])/", ' ', $str->string), " \n\r\t\x0C");
+
+ return $str;
+ }
+
+ /**
+ * @param string|string[] $needle
+ */
+ public function containsAny($needle): bool
+ {
+ return null !== $this->indexOf($needle);
+ }
+
+ /**
+ * @param string|string[] $suffix
+ */
+ public function endsWith($suffix): bool
+ {
+ if (!\is_array($suffix) && !$suffix instanceof \Traversable) {
+ throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class));
+ }
+
+ foreach ($suffix as $s) {
+ if ($this->endsWith((string) $s)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @return static
+ */
+ public function ensureEnd(string $suffix): self
+ {
+ if (!$this->endsWith($suffix)) {
+ return $this->append($suffix);
+ }
+
+ $suffix = preg_quote($suffix);
+ $regex = '{('.$suffix.')(?:'.$suffix.')++$}D';
+
+ return $this->replaceMatches($regex.($this->ignoreCase ? 'i' : ''), '$1');
+ }
+
+ /**
+ * @return static
+ */
+ public function ensureStart(string $prefix): self
+ {
+ $prefix = new static($prefix);
+
+ if (!$this->startsWith($prefix)) {
+ return $this->prepend($prefix);
+ }
+
+ $str = clone $this;
+ $i = $prefixLen = $prefix->length();
+
+ while ($this->indexOf($prefix, $i) === $i) {
+ $str = $str->slice($prefixLen);
+ $i += $prefixLen;
+ }
+
+ return $str;
+ }
+
+ /**
+ * @param string|string[] $string
+ */
+ public function equalsTo($string): bool
+ {
+ if (!\is_array($string) && !$string instanceof \Traversable) {
+ throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class));
+ }
+
+ foreach ($string as $s) {
+ if ($this->equalsTo((string) $s)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @return static
+ */
+ abstract public function folded(): self;
+
+ /**
+ * @return static
+ */
+ public function ignoreCase(): self
+ {
+ $str = clone $this;
+ $str->ignoreCase = true;
+
+ return $str;
+ }
+
+ /**
+ * @param string|string[] $needle
+ */
+ public function indexOf($needle, int $offset = 0): ?int
+ {
+ if (!\is_array($needle) && !$needle instanceof \Traversable) {
+ throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class));
+ }
+
+ $i = \PHP_INT_MAX;
+
+ foreach ($needle as $n) {
+ $j = $this->indexOf((string) $n, $offset);
+
+ if (null !== $j && $j < $i) {
+ $i = $j;
+ }
+ }
+
+ return \PHP_INT_MAX === $i ? null : $i;
+ }
+
+ /**
+ * @param string|string[] $needle
+ */
+ public function indexOfLast($needle, int $offset = 0): ?int
+ {
+ if (!\is_array($needle) && !$needle instanceof \Traversable) {
+ throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class));
+ }
+
+ $i = null;
+
+ foreach ($needle as $n) {
+ $j = $this->indexOfLast((string) $n, $offset);
+
+ if (null !== $j && $j >= $i) {
+ $i = $offset = $j;
+ }
+ }
+
+ return $i;
+ }
+
+ public function isEmpty(): bool
+ {
+ return '' === $this->string;
+ }
+
+ /**
+ * @return static
+ */
+ abstract public function join(array $strings, string $lastGlue = null): self;
+
+ public function jsonSerialize(): string
+ {
+ return $this->string;
+ }
+
+ abstract public function length(): int;
+
+ /**
+ * @return static
+ */
+ abstract public function lower(): self;
+
+ /**
+ * Matches the string using a regular expression.
+ *
+ * Pass PREG_PATTERN_ORDER or PREG_SET_ORDER as $flags to get all occurrences matching the regular expression.
+ *
+ * @return array All matches in a multi-dimensional array ordered according to flags
+ */
+ abstract public function match(string $regexp, int $flags = 0, int $offset = 0): array;
+
+ /**
+ * @return static
+ */
+ abstract public function padBoth(int $length, string $padStr = ' '): self;
+
+ /**
+ * @return static
+ */
+ abstract public function padEnd(int $length, string $padStr = ' '): self;
+
+ /**
+ * @return static
+ */
+ abstract public function padStart(int $length, string $padStr = ' '): self;
+
+ /**
+ * @return static
+ */
+ abstract public function prepend(string ...$prefix): self;
+
+ /**
+ * @return static
+ */
+ public function repeat(int $multiplier): self
+ {
+ if (0 > $multiplier) {
+ throw new InvalidArgumentException(sprintf('Multiplier must be positive, %d given.', $multiplier));
+ }
+
+ $str = clone $this;
+ $str->string = str_repeat($str->string, $multiplier);
+
+ return $str;
+ }
+
+ /**
+ * @return static
+ */
+ abstract public function replace(string $from, string $to): self;
+
+ /**
+ * @param string|callable $to
+ *
+ * @return static
+ */
+ abstract public function replaceMatches(string $fromRegexp, $to): self;
+
+ /**
+ * @return static
+ */
+ abstract public function reverse(): self;
+
+ /**
+ * @return static
+ */
+ abstract public function slice(int $start = 0, int $length = null): self;
+
+ /**
+ * @return static
+ */
+ abstract public function snake(): self;
+
+ /**
+ * @return static
+ */
+ abstract public function splice(string $replacement, int $start = 0, int $length = null): self;
+
+ /**
+ * @return static[]
+ */
+ public function split(string $delimiter, int $limit = null, int $flags = null): array
+ {
+ if (null === $flags) {
+ throw new \TypeError('Split behavior when $flags is null must be implemented by child classes.');
+ }
+
+ if ($this->ignoreCase) {
+ $delimiter .= 'i';
+ }
+
+ set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); });
+
+ try {
+ if (false === $chunks = preg_split($delimiter, $this->string, $limit, $flags)) {
+ $lastError = preg_last_error();
+
+ foreach (get_defined_constants(true)['pcre'] as $k => $v) {
+ if ($lastError === $v && '_ERROR' === substr($k, -6)) {
+ throw new RuntimeException('Splitting failed with '.$k.'.');
+ }
+ }
+
+ throw new RuntimeException('Splitting failed with unknown error code.');
+ }
+ } finally {
+ restore_error_handler();
+ }
+
+ $str = clone $this;
+
+ if (self::PREG_SPLIT_OFFSET_CAPTURE & $flags) {
+ foreach ($chunks as &$chunk) {
+ $str->string = $chunk[0];
+ $chunk[0] = clone $str;
+ }
+ } else {
+ foreach ($chunks as &$chunk) {
+ $str->string = $chunk;
+ $chunk = clone $str;
+ }
+ }
+
+ return $chunks;
+ }
+
+ /**
+ * @param string|string[] $prefix
+ */
+ public function startsWith($prefix): bool
+ {
+ if (!\is_array($prefix) && !$prefix instanceof \Traversable) {
+ throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class));
+ }
+
+ foreach ($prefix as $prefix) {
+ if ($this->startsWith((string) $prefix)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @return static
+ */
+ abstract public function title(bool $allWords = false): self;
+
+ public function toByteString(string $toEncoding = null): ByteString
+ {
+ $b = new ByteString();
+
+ $toEncoding = \in_array($toEncoding, ['utf8', 'utf-8', 'UTF8'], true) ? 'UTF-8' : $toEncoding;
+
+ if (null === $toEncoding || $toEncoding === $fromEncoding = $this instanceof AbstractUnicodeString || preg_match('//u', $b->string) ? 'UTF-8' : 'Windows-1252') {
+ $b->string = $this->string;
+
+ return $b;
+ }
+
+ set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); });
+
+ try {
+ try {
+ $b->string = mb_convert_encoding($this->string, $toEncoding, 'UTF-8');
+ } catch (InvalidArgumentException $e) {
+ if (!\function_exists('iconv')) {
+ throw $e;
+ }
+
+ $b->string = iconv('UTF-8', $toEncoding, $this->string);
+ }
+ } finally {
+ restore_error_handler();
+ }
+
+ return $b;
+ }
+
+ public function toCodePointString(): CodePointString
+ {
+ return new CodePointString($this->string);
+ }
+
+ public function toString(): string
+ {
+ return $this->string;
+ }
+
+ public function toUnicodeString(): UnicodeString
+ {
+ return new UnicodeString($this->string);
+ }
+
+ /**
+ * @return static
+ */
+ abstract public function trim(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): self;
+
+ /**
+ * @return static
+ */
+ abstract public function trimEnd(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): self;
+
+ /**
+ * @param string|string[] $prefix
+ *
+ * @return static
+ */
+ public function trimPrefix($prefix): self
+ {
+ if (\is_array($prefix) || $prefix instanceof \Traversable) {
+ foreach ($prefix as $s) {
+ $t = $this->trimPrefix($s);
+
+ if ($t->string !== $this->string) {
+ return $t;
+ }
+ }
+
+ return clone $this;
+ }
+
+ $str = clone $this;
+
+ if ($prefix instanceof self) {
+ $prefix = $prefix->string;
+ } else {
+ $prefix = (string) $prefix;
+ }
+
+ if ('' !== $prefix && \strlen($this->string) >= \strlen($prefix) && 0 === substr_compare($this->string, $prefix, 0, \strlen($prefix), $this->ignoreCase)) {
+ $str->string = substr($this->string, \strlen($prefix));
+ }
+
+ return $str;
+ }
+
+ /**
+ * @return static
+ */
+ abstract public function trimStart(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): self;
+
+ /**
+ * @param string|string[] $suffix
+ *
+ * @return static
+ */
+ public function trimSuffix($suffix): self
+ {
+ if (\is_array($suffix) || $suffix instanceof \Traversable) {
+ foreach ($suffix as $s) {
+ $t = $this->trimSuffix($s);
+
+ if ($t->string !== $this->string) {
+ return $t;
+ }
+ }
+
+ return clone $this;
+ }
+
+ $str = clone $this;
+
+ if ($suffix instanceof self) {
+ $suffix = $suffix->string;
+ } else {
+ $suffix = (string) $suffix;
+ }
+
+ if ('' !== $suffix && \strlen($this->string) >= \strlen($suffix) && 0 === substr_compare($this->string, $suffix, -\strlen($suffix), null, $this->ignoreCase)) {
+ $str->string = substr($this->string, 0, -\strlen($suffix));
+ }
+
+ return $str;
+ }
+
+ /**
+ * @return static
+ */
+ public function truncate(int $length, string $ellipsis = '', bool $cut = true): self
+ {
+ $stringLength = $this->length();
+
+ if ($stringLength <= $length) {
+ return clone $this;
+ }
+
+ $ellipsisLength = '' !== $ellipsis ? (new static($ellipsis))->length() : 0;
+
+ if ($length < $ellipsisLength) {
+ $ellipsisLength = 0;
+ }
+
+ if (!$cut) {
+ if (null === $length = $this->indexOf([' ', "\r", "\n", "\t"], ($length ?: 1) - 1)) {
+ return clone $this;
+ }
+
+ $length += $ellipsisLength;
+ }
+
+ $str = $this->slice(0, $length - $ellipsisLength);
+
+ return $ellipsisLength ? $str->trimEnd()->append($ellipsis) : $str;
+ }
+
+ /**
+ * @return static
+ */
+ abstract public function upper(): self;
+
+ /**
+ * Returns the printable length on a terminal.
+ */
+ abstract public function width(bool $ignoreAnsiDecoration = true): int;
+
+ /**
+ * @return static
+ */
+ public function wordwrap(int $width = 75, string $break = "\n", bool $cut = false): self
+ {
+ $lines = '' !== $break ? $this->split($break) : [clone $this];
+ $chars = [];
+ $mask = '';
+
+ if (1 === \count($lines) && '' === $lines[0]->string) {
+ return $lines[0];
+ }
+
+ foreach ($lines as $i => $line) {
+ if ($i) {
+ $chars[] = $break;
+ $mask .= '#';
+ }
+
+ foreach ($line->chunk() as $char) {
+ $chars[] = $char->string;
+ $mask .= ' ' === $char->string ? ' ' : '?';
+ }
+ }
+
+ $string = '';
+ $j = 0;
+ $b = $i = -1;
+ $mask = wordwrap($mask, $width, '#', $cut);
+
+ while (false !== $b = strpos($mask, '#', $b + 1)) {
+ for (++$i; $i < $b; ++$i) {
+ $string .= $chars[$j];
+ unset($chars[$j++]);
+ }
+
+ if ($break === $chars[$j] || ' ' === $chars[$j]) {
+ unset($chars[$j++]);
+ }
+
+ $string .= $break;
+ }
+
+ $str = clone $this;
+ $str->string = $string.implode('', $chars);
+
+ return $str;
+ }
+
+ public function __sleep(): array
+ {
+ return ['string'];
+ }
+
+ public function __clone()
+ {
+ $this->ignoreCase = false;
+ }
+
+ public function __toString(): string
+ {
+ return $this->string;
+ }
+}
diff --git a/vendor/symfony/string/AbstractUnicodeString.php b/vendor/symfony/string/AbstractUnicodeString.php
new file mode 100644
index 000000000..80b8326ae
--- /dev/null
+++ b/vendor/symfony/string/AbstractUnicodeString.php
@@ -0,0 +1,623 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\String;
+
+use Symfony\Component\String\Exception\ExceptionInterface;
+use Symfony\Component\String\Exception\InvalidArgumentException;
+use Symfony\Component\String\Exception\RuntimeException;
+
+/**
+ * Represents a string of abstract Unicode characters.
+ *
+ * Unicode defines 3 types of "characters" (bytes, code points and grapheme clusters).
+ * This class is the abstract type to use as a type-hint when the logic you want to
+ * implement is Unicode-aware but doesn't care about code points vs grapheme clusters.
+ *
+ * @author Nicolas Grekas
+ *
+ * @throws ExceptionInterface
+ */
+abstract class AbstractUnicodeString extends AbstractString
+{
+ public const NFC = \Normalizer::NFC;
+ public const NFD = \Normalizer::NFD;
+ public const NFKC = \Normalizer::NFKC;
+ public const NFKD = \Normalizer::NFKD;
+
+ // all ASCII letters sorted by typical frequency of occurrence
+ private const ASCII = "\x20\x65\x69\x61\x73\x6E\x74\x72\x6F\x6C\x75\x64\x5D\x5B\x63\x6D\x70\x27\x0A\x67\x7C\x68\x76\x2E\x66\x62\x2C\x3A\x3D\x2D\x71\x31\x30\x43\x32\x2A\x79\x78\x29\x28\x4C\x39\x41\x53\x2F\x50\x22\x45\x6A\x4D\x49\x6B\x33\x3E\x35\x54\x3C\x44\x34\x7D\x42\x7B\x38\x46\x77\x52\x36\x37\x55\x47\x4E\x3B\x4A\x7A\x56\x23\x48\x4F\x57\x5F\x26\x21\x4B\x3F\x58\x51\x25\x59\x5C\x09\x5A\x2B\x7E\x5E\x24\x40\x60\x7F\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F";
+
+ // the subset of folded case mappings that is not in lower case mappings
+ private const FOLD_FROM = ['İ', 'µ', 'ſ', "\xCD\x85", 'ς', 'ϐ', 'ϑ', 'ϕ', 'ϖ', 'ϰ', 'ϱ', 'ϵ', 'ẛ', "\xE1\xBE\xBE", 'ß', 'ʼn', 'ǰ', 'ΐ', 'ΰ', 'և', 'ẖ', 'ẗ', 'ẘ', 'ẙ', 'ẚ', 'ẞ', 'ὐ', 'ὒ', 'ὔ', 'ὖ', 'ᾀ', 'ᾁ', 'ᾂ', 'ᾃ', 'ᾄ', 'ᾅ', 'ᾆ', 'ᾇ', 'ᾈ', 'ᾉ', 'ᾊ', 'ᾋ', 'ᾌ', 'ᾍ', 'ᾎ', 'ᾏ', 'ᾐ', 'ᾑ', 'ᾒ', 'ᾓ', 'ᾔ', 'ᾕ', 'ᾖ', 'ᾗ', 'ᾘ', 'ᾙ', 'ᾚ', 'ᾛ', 'ᾜ', 'ᾝ', 'ᾞ', 'ᾟ', 'ᾠ', 'ᾡ', 'ᾢ', 'ᾣ', 'ᾤ', 'ᾥ', 'ᾦ', 'ᾧ', 'ᾨ', 'ᾩ', 'ᾪ', 'ᾫ', 'ᾬ', 'ᾭ', 'ᾮ', 'ᾯ', 'ᾲ', 'ᾳ', 'ᾴ', 'ᾶ', 'ᾷ', 'ᾼ', 'ῂ', 'ῃ', 'ῄ', 'ῆ', 'ῇ', 'ῌ', 'ῒ', 'ῖ', 'ῗ', 'ῢ', 'ῤ', 'ῦ', 'ῧ', 'ῲ', 'ῳ', 'ῴ', 'ῶ', 'ῷ', 'ῼ', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'ſt', 'st', 'ﬓ', 'ﬔ', 'ﬕ', 'ﬖ', 'ﬗ'];
+ private const FOLD_TO = ['i̇', 'μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', 'ṡ', 'ι', 'ss', 'ʼn', 'ǰ', 'ΐ', 'ΰ', 'եւ', 'ẖ', 'ẗ', 'ẘ', 'ẙ', 'aʾ', 'ss', 'ὐ', 'ὒ', 'ὔ', 'ὖ', 'ἀι', 'ἁι', 'ἂι', 'ἃι', 'ἄι', 'ἅι', 'ἆι', 'ἇι', 'ἀι', 'ἁι', 'ἂι', 'ἃι', 'ἄι', 'ἅι', 'ἆι', 'ἇι', 'ἠι', 'ἡι', 'ἢι', 'ἣι', 'ἤι', 'ἥι', 'ἦι', 'ἧι', 'ἠι', 'ἡι', 'ἢι', 'ἣι', 'ἤι', 'ἥι', 'ἦι', 'ἧι', 'ὠι', 'ὡι', 'ὢι', 'ὣι', 'ὤι', 'ὥι', 'ὦι', 'ὧι', 'ὠι', 'ὡι', 'ὢι', 'ὣι', 'ὤι', 'ὥι', 'ὦι', 'ὧι', 'ὰι', 'αι', 'άι', 'ᾶ', 'ᾶι', 'αι', 'ὴι', 'ηι', 'ήι', 'ῆ', 'ῆι', 'ηι', 'ῒ', 'ῖ', 'ῗ', 'ῢ', 'ῤ', 'ῦ', 'ῧ', 'ὼι', 'ωι', 'ώι', 'ῶ', 'ῶι', 'ωι', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'st', 'st', 'մն', 'մե', 'մի', 'վն', 'մխ'];
+
+ // the subset of upper case mappings that map one code point to many code points
+ private const UPPER_FROM = ['ß', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'ſt', 'st', 'և', 'ﬓ', 'ﬔ', 'ﬕ', 'ﬖ', 'ﬗ', 'ʼn', 'ΐ', 'ΰ', 'ǰ', 'ẖ', 'ẗ', 'ẘ', 'ẙ', 'ẚ', 'ὐ', 'ὒ', 'ὔ', 'ὖ', 'ᾶ', 'ῆ', 'ῒ', 'ΐ', 'ῖ', 'ῗ', 'ῢ', 'ΰ', 'ῤ', 'ῦ', 'ῧ', 'ῶ'];
+ private const UPPER_TO = ['SS', 'FF', 'FI', 'FL', 'FFI', 'FFL', 'ST', 'ST', 'ԵՒ', 'ՄՆ', 'ՄԵ', 'ՄԻ', 'ՎՆ', 'ՄԽ', 'ʼN', 'Ϊ́', 'Ϋ́', 'J̌', 'H̱', 'T̈', 'W̊', 'Y̊', 'Aʾ', 'Υ̓', 'Υ̓̀', 'Υ̓́', 'Υ̓͂', 'Α͂', 'Η͂', 'Ϊ̀', 'Ϊ́', 'Ι͂', 'Ϊ͂', 'Ϋ̀', 'Ϋ́', 'Ρ̓', 'Υ͂', 'Ϋ͂', 'Ω͂'];
+
+ // the subset of https://github.com/unicode-org/cldr/blob/master/common/transforms/Latin-ASCII.xml that is not in NFKD
+ private const TRANSLIT_FROM = ['Æ', 'Ð', 'Ø', 'Þ', 'ß', 'æ', 'ð', 'ø', 'þ', 'Đ', 'đ', 'Ħ', 'ħ', 'ı', 'ĸ', 'Ŀ', 'ŀ', 'Ł', 'ł', 'ʼn', 'Ŋ', 'ŋ', 'Œ', 'œ', 'Ŧ', 'ŧ', 'ƀ', 'Ɓ', 'Ƃ', 'ƃ', 'Ƈ', 'ƈ', 'Ɖ', 'Ɗ', 'Ƌ', 'ƌ', 'Ɛ', 'Ƒ', 'ƒ', 'Ɠ', 'ƕ', 'Ɩ', 'Ɨ', 'Ƙ', 'ƙ', 'ƚ', 'Ɲ', 'ƞ', 'Ƣ', 'ƣ', 'Ƥ', 'ƥ', 'ƫ', 'Ƭ', 'ƭ', 'Ʈ', 'Ʋ', 'Ƴ', 'ƴ', 'Ƶ', 'ƶ', 'DŽ', 'Dž', 'dž', 'Ǥ', 'ǥ', 'ȡ', 'Ȥ', 'ȥ', 'ȴ', 'ȵ', 'ȶ', 'ȷ', 'ȸ', 'ȹ', 'Ⱥ', 'Ȼ', 'ȼ', 'Ƚ', 'Ⱦ', 'ȿ', 'ɀ', 'Ƀ', 'Ʉ', 'Ɇ', 'ɇ', 'Ɉ', 'ɉ', 'Ɍ', 'ɍ', 'Ɏ', 'ɏ', 'ɓ', 'ɕ', 'ɖ', 'ɗ', 'ɛ', 'ɟ', 'ɠ', 'ɡ', 'ɢ', 'ɦ', 'ɧ', 'ɨ', 'ɪ', 'ɫ', 'ɬ', 'ɭ', 'ɱ', 'ɲ', 'ɳ', 'ɴ', 'ɶ', 'ɼ', 'ɽ', 'ɾ', 'ʀ', 'ʂ', 'ʈ', 'ʉ', 'ʋ', 'ʏ', 'ʐ', 'ʑ', 'ʙ', 'ʛ', 'ʜ', 'ʝ', 'ʟ', 'ʠ', 'ʣ', 'ʥ', 'ʦ', 'ʪ', 'ʫ', 'ᴀ', 'ᴁ', 'ᴃ', 'ᴄ', 'ᴅ', 'ᴆ', 'ᴇ', 'ᴊ', 'ᴋ', 'ᴌ', 'ᴍ', 'ᴏ', 'ᴘ', 'ᴛ', 'ᴜ', 'ᴠ', 'ᴡ', 'ᴢ', 'ᵫ', 'ᵬ', 'ᵭ', 'ᵮ', 'ᵯ', 'ᵰ', 'ᵱ', 'ᵲ', 'ᵳ', 'ᵴ', 'ᵵ', 'ᵶ', 'ᵺ', 'ᵻ', 'ᵽ', 'ᵾ', 'ᶀ', 'ᶁ', 'ᶂ', 'ᶃ', 'ᶄ', 'ᶅ', 'ᶆ', 'ᶇ', 'ᶈ', 'ᶉ', 'ᶊ', 'ᶌ', 'ᶍ', 'ᶎ', 'ᶏ', 'ᶑ', 'ᶒ', 'ᶓ', 'ᶖ', 'ᶙ', 'ẚ', 'ẜ', 'ẝ', 'ẞ', 'Ỻ', 'ỻ', 'Ỽ', 'ỽ', 'Ỿ', 'ỿ', '©', '®', '₠', '₢', '₣', '₤', '₧', '₺', '₹', 'ℌ', '℞', '㎧', '㎮', '㏆', '㏗', '㏞', '㏟', '¼', '½', '¾', '⅓', '⅔', '⅕', '⅖', '⅗', '⅘', '⅙', '⅚', '⅛', '⅜', '⅝', '⅞', '⅟', '〇', '‘', '’', '‚', '‛', '“', '”', '„', '‟', '′', '″', '〝', '〞', '«', '»', '‹', '›', '‐', '‑', '‒', '–', '—', '―', '︱', '︲', '﹘', '‖', '⁄', '⁅', '⁆', '⁎', '、', '。', '〈', '〉', '《', '》', '〔', '〕', '〘', '〙', '〚', '〛', '︑', '︒', '︹', '︺', '︽', '︾', '︿', '﹀', '﹑', '﹝', '﹞', '⦅', '⦆', '。', '、', '×', '÷', '−', '∕', '∖', '∣', '∥', '≪', '≫', '⦅', '⦆'];
+ private const TRANSLIT_TO = ['AE', 'D', 'O', 'TH', 'ss', 'ae', 'd', 'o', 'th', 'D', 'd', 'H', 'h', 'i', 'q', 'L', 'l', 'L', 'l', '\'n', 'N', 'n', 'OE', 'oe', 'T', 't', 'b', 'B', 'B', 'b', 'C', 'c', 'D', 'D', 'D', 'd', 'E', 'F', 'f', 'G', 'hv', 'I', 'I', 'K', 'k', 'l', 'N', 'n', 'OI', 'oi', 'P', 'p', 't', 'T', 't', 'T', 'V', 'Y', 'y', 'Z', 'z', 'DZ', 'Dz', 'dz', 'G', 'g', 'd', 'Z', 'z', 'l', 'n', 't', 'j', 'db', 'qp', 'A', 'C', 'c', 'L', 'T', 's', 'z', 'B', 'U', 'E', 'e', 'J', 'j', 'R', 'r', 'Y', 'y', 'b', 'c', 'd', 'd', 'e', 'j', 'g', 'g', 'G', 'h', 'h', 'i', 'I', 'l', 'l', 'l', 'm', 'n', 'n', 'N', 'OE', 'r', 'r', 'r', 'R', 's', 't', 'u', 'v', 'Y', 'z', 'z', 'B', 'G', 'H', 'j', 'L', 'q', 'dz', 'dz', 'ts', 'ls', 'lz', 'A', 'AE', 'B', 'C', 'D', 'D', 'E', 'J', 'K', 'L', 'M', 'O', 'P', 'T', 'U', 'V', 'W', 'Z', 'ue', 'b', 'd', 'f', 'm', 'n', 'p', 'r', 'r', 's', 't', 'z', 'th', 'I', 'p', 'U', 'b', 'd', 'f', 'g', 'k', 'l', 'm', 'n', 'p', 'r', 's', 'v', 'x', 'z', 'a', 'd', 'e', 'e', 'i', 'u', 'a', 's', 's', 'SS', 'LL', 'll', 'V', 'v', 'Y', 'y', '(C)', '(R)', 'CE', 'Cr', 'Fr.', 'L.', 'Pts', 'TL', 'Rs', 'x', 'Rx', 'm/s', 'rad/s', 'C/kg', 'pH', 'V/m', 'A/m', ' 1/4', ' 1/2', ' 3/4', ' 1/3', ' 2/3', ' 1/5', ' 2/5', ' 3/5', ' 4/5', ' 1/6', ' 5/6', ' 1/8', ' 3/8', ' 5/8', ' 7/8', ' 1/', '0', '\'', '\'', ',', '\'', '"', '"', ',,', '"', '\'', '"', '"', '"', '<<', '>>', '<', '>', '-', '-', '-', '-', '-', '-', '-', '-', '-', '||', '/', '[', ']', '*', ',', '.', '<', '>', '<<', '>>', '[', ']', '[', ']', '[', ']', ',', '.', '[', ']', '<<', '>>', '<', '>', ',', '[', ']', '((', '))', '.', ',', '*', '/', '-', '/', '\\', '|', '||', '<<', '>>', '((', '))'];
+
+ private static $transliterators = [];
+ private static $tableZero;
+ private static $tableWide;
+
+ /**
+ * @return static
+ */
+ public static function fromCodePoints(int ...$codes): self
+ {
+ $string = '';
+
+ foreach ($codes as $code) {
+ if (0x80 > $code %= 0x200000) {
+ $string .= \chr($code);
+ } elseif (0x800 > $code) {
+ $string .= \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F);
+ } elseif (0x10000 > $code) {
+ $string .= \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
+ } else {
+ $string .= \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
+ }
+ }
+
+ return new static($string);
+ }
+
+ /**
+ * Generic UTF-8 to ASCII transliteration.
+ *
+ * Install the intl extension for best results.
+ *
+ * @param string[]|\Transliterator[]|\Closure[] $rules See "*-Latin" rules from Transliterator::listIDs()
+ */
+ public function ascii(array $rules = []): self
+ {
+ $str = clone $this;
+ $s = $str->string;
+ $str->string = '';
+
+ array_unshift($rules, 'nfd');
+ $rules[] = 'latin-ascii';
+
+ if (\function_exists('transliterator_transliterate')) {
+ $rules[] = 'any-latin/bgn';
+ }
+
+ $rules[] = 'nfkd';
+ $rules[] = '[:nonspacing mark:] remove';
+
+ while (\strlen($s) - 1 > $i = strspn($s, self::ASCII)) {
+ if (0 < --$i) {
+ $str->string .= substr($s, 0, $i);
+ $s = substr($s, $i);
+ }
+
+ if (!$rule = array_shift($rules)) {
+ $rules = []; // An empty rule interrupts the next ones
+ }
+
+ if ($rule instanceof \Transliterator) {
+ $s = $rule->transliterate($s);
+ } elseif ($rule instanceof \Closure) {
+ $s = $rule($s);
+ } elseif ($rule) {
+ if ('nfd' === $rule = strtolower($rule)) {
+ normalizer_is_normalized($s, self::NFD) ?: $s = normalizer_normalize($s, self::NFD);
+ } elseif ('nfkd' === $rule) {
+ normalizer_is_normalized($s, self::NFKD) ?: $s = normalizer_normalize($s, self::NFKD);
+ } elseif ('[:nonspacing mark:] remove' === $rule) {
+ $s = preg_replace('/\p{Mn}++/u', '', $s);
+ } elseif ('latin-ascii' === $rule) {
+ $s = str_replace(self::TRANSLIT_FROM, self::TRANSLIT_TO, $s);
+ } elseif ('de-ascii' === $rule) {
+ $s = preg_replace("/([AUO])\u{0308}(?=\p{Ll})/u", '$1e', $s);
+ $s = str_replace(["a\u{0308}", "o\u{0308}", "u\u{0308}", "A\u{0308}", "O\u{0308}", "U\u{0308}"], ['ae', 'oe', 'ue', 'AE', 'OE', 'UE'], $s);
+ } elseif (\function_exists('transliterator_transliterate')) {
+ if (null === $transliterator = self::$transliterators[$rule] ?? self::$transliterators[$rule] = \Transliterator::create($rule)) {
+ if ('any-latin/bgn' === $rule) {
+ $rule = 'any-latin';
+ $transliterator = self::$transliterators[$rule] ?? self::$transliterators[$rule] = \Transliterator::create($rule);
+ }
+
+ if (null === $transliterator) {
+ throw new InvalidArgumentException(sprintf('Unknown transliteration rule "%s".', $rule));
+ }
+
+ self::$transliterators['any-latin/bgn'] = $transliterator;
+ }
+
+ $s = $transliterator->transliterate($s);
+ }
+ } elseif (!\function_exists('iconv')) {
+ $s = preg_replace('/[^\x00-\x7F]/u', '?', $s);
+ } else {
+ $s = @preg_replace_callback('/[^\x00-\x7F]/u', static function ($c) {
+ $c = (string) iconv('UTF-8', 'ASCII//TRANSLIT', $c[0]);
+
+ if ('' === $c && '' === iconv('UTF-8', 'ASCII//TRANSLIT', '²')) {
+ throw new \LogicException(sprintf('"%s" requires a translit-able iconv implementation, try installing "gnu-libiconv" if you\'re using Alpine Linux.', static::class));
+ }
+
+ return 1 < \strlen($c) ? ltrim($c, '\'`"^~') : ('' !== $c ? $c : '?');
+ }, $s);
+ }
+ }
+
+ $str->string .= $s;
+
+ return $str;
+ }
+
+ public function camel(): parent
+ {
+ $str = clone $this;
+ $str->string = str_replace(' ', '', preg_replace_callback('/\b.(?![A-Z]{2,})/u', static function ($m) use (&$i) {
+ return 1 === ++$i ? ('İ' === $m[0] ? 'i̇' : mb_strtolower($m[0], 'UTF-8')) : mb_convert_case($m[0], \MB_CASE_TITLE, 'UTF-8');
+ }, preg_replace('/[^\pL0-9]++/u', ' ', $this->string)));
+
+ return $str;
+ }
+
+ /**
+ * @return int[]
+ */
+ public function codePointsAt(int $offset): array
+ {
+ $str = $this->slice($offset, 1);
+
+ if ('' === $str->string) {
+ return [];
+ }
+
+ $codePoints = [];
+
+ foreach (preg_split('//u', $str->string, -1, \PREG_SPLIT_NO_EMPTY) as $c) {
+ $codePoints[] = mb_ord($c, 'UTF-8');
+ }
+
+ return $codePoints;
+ }
+
+ public function folded(bool $compat = true): parent
+ {
+ $str = clone $this;
+
+ if (!$compat || \PHP_VERSION_ID < 70300 || !\defined('Normalizer::NFKC_CF')) {
+ $str->string = normalizer_normalize($str->string, $compat ? \Normalizer::NFKC : \Normalizer::NFC);
+ $str->string = mb_strtolower(str_replace(self::FOLD_FROM, self::FOLD_TO, $this->string), 'UTF-8');
+ } else {
+ $str->string = normalizer_normalize($str->string, \Normalizer::NFKC_CF);
+ }
+
+ return $str;
+ }
+
+ public function join(array $strings, string $lastGlue = null): parent
+ {
+ $str = clone $this;
+
+ $tail = null !== $lastGlue && 1 < \count($strings) ? $lastGlue.array_pop($strings) : '';
+ $str->string = implode($this->string, $strings).$tail;
+
+ if (!preg_match('//u', $str->string)) {
+ throw new InvalidArgumentException('Invalid UTF-8 string.');
+ }
+
+ return $str;
+ }
+
+ public function lower(): parent
+ {
+ $str = clone $this;
+ $str->string = mb_strtolower(str_replace('İ', 'i̇', $str->string), 'UTF-8');
+
+ return $str;
+ }
+
+ public function match(string $regexp, int $flags = 0, int $offset = 0): array
+ {
+ $match = ((\PREG_PATTERN_ORDER | \PREG_SET_ORDER) & $flags) ? 'preg_match_all' : 'preg_match';
+
+ if ($this->ignoreCase) {
+ $regexp .= 'i';
+ }
+
+ set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); });
+
+ try {
+ if (false === $match($regexp.'u', $this->string, $matches, $flags | \PREG_UNMATCHED_AS_NULL, $offset)) {
+ $lastError = preg_last_error();
+
+ foreach (get_defined_constants(true)['pcre'] as $k => $v) {
+ if ($lastError === $v && '_ERROR' === substr($k, -6)) {
+ throw new RuntimeException('Matching failed with '.$k.'.');
+ }
+ }
+
+ throw new RuntimeException('Matching failed with unknown error code.');
+ }
+ } finally {
+ restore_error_handler();
+ }
+
+ return $matches;
+ }
+
+ /**
+ * @return static
+ */
+ public function normalize(int $form = self::NFC): self
+ {
+ if (!\in_array($form, [self::NFC, self::NFD, self::NFKC, self::NFKD])) {
+ throw new InvalidArgumentException('Unsupported normalization form.');
+ }
+
+ $str = clone $this;
+ normalizer_is_normalized($str->string, $form) ?: $str->string = normalizer_normalize($str->string, $form);
+
+ return $str;
+ }
+
+ public function padBoth(int $length, string $padStr = ' '): parent
+ {
+ if ('' === $padStr || !preg_match('//u', $padStr)) {
+ throw new InvalidArgumentException('Invalid UTF-8 string.');
+ }
+
+ $pad = clone $this;
+ $pad->string = $padStr;
+
+ return $this->pad($length, $pad, \STR_PAD_BOTH);
+ }
+
+ public function padEnd(int $length, string $padStr = ' '): parent
+ {
+ if ('' === $padStr || !preg_match('//u', $padStr)) {
+ throw new InvalidArgumentException('Invalid UTF-8 string.');
+ }
+
+ $pad = clone $this;
+ $pad->string = $padStr;
+
+ return $this->pad($length, $pad, \STR_PAD_RIGHT);
+ }
+
+ public function padStart(int $length, string $padStr = ' '): parent
+ {
+ if ('' === $padStr || !preg_match('//u', $padStr)) {
+ throw new InvalidArgumentException('Invalid UTF-8 string.');
+ }
+
+ $pad = clone $this;
+ $pad->string = $padStr;
+
+ return $this->pad($length, $pad, \STR_PAD_LEFT);
+ }
+
+ public function replaceMatches(string $fromRegexp, $to): parent
+ {
+ if ($this->ignoreCase) {
+ $fromRegexp .= 'i';
+ }
+
+ if (\is_array($to) || $to instanceof \Closure) {
+ if (!\is_callable($to)) {
+ throw new \TypeError(sprintf('Argument 2 passed to "%s::replaceMatches()" must be callable, array given.', static::class));
+ }
+
+ $replace = 'preg_replace_callback';
+ $to = static function (array $m) use ($to): string {
+ $to = $to($m);
+
+ if ('' !== $to && (!\is_string($to) || !preg_match('//u', $to))) {
+ throw new InvalidArgumentException('Replace callback must return a valid UTF-8 string.');
+ }
+
+ return $to;
+ };
+ } elseif ('' !== $to && !preg_match('//u', $to)) {
+ throw new InvalidArgumentException('Invalid UTF-8 string.');
+ } else {
+ $replace = 'preg_replace';
+ }
+
+ set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); });
+
+ try {
+ if (null === $string = $replace($fromRegexp.'u', $to, $this->string)) {
+ $lastError = preg_last_error();
+
+ foreach (get_defined_constants(true)['pcre'] as $k => $v) {
+ if ($lastError === $v && '_ERROR' === substr($k, -6)) {
+ throw new RuntimeException('Matching failed with '.$k.'.');
+ }
+ }
+
+ throw new RuntimeException('Matching failed with unknown error code.');
+ }
+ } finally {
+ restore_error_handler();
+ }
+
+ $str = clone $this;
+ $str->string = $string;
+
+ return $str;
+ }
+
+ public function reverse(): parent
+ {
+ $str = clone $this;
+ $str->string = implode('', array_reverse(preg_split('/(\X)/u', $str->string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY)));
+
+ return $str;
+ }
+
+ public function snake(): parent
+ {
+ $str = $this->camel();
+ $str->string = mb_strtolower(preg_replace(['/(\p{Lu}+)(\p{Lu}\p{Ll})/u', '/([\p{Ll}0-9])(\p{Lu})/u'], '\1_\2', $str->string), 'UTF-8');
+
+ return $str;
+ }
+
+ public function title(bool $allWords = false): parent
+ {
+ $str = clone $this;
+
+ $limit = $allWords ? -1 : 1;
+
+ $str->string = preg_replace_callback('/\b./u', static function (array $m): string {
+ return mb_convert_case($m[0], \MB_CASE_TITLE, 'UTF-8');
+ }, $str->string, $limit);
+
+ return $str;
+ }
+
+ public function trim(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): parent
+ {
+ if (" \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}" !== $chars && !preg_match('//u', $chars)) {
+ throw new InvalidArgumentException('Invalid UTF-8 chars.');
+ }
+ $chars = preg_quote($chars);
+
+ $str = clone $this;
+ $str->string = preg_replace("{^[$chars]++|[$chars]++$}uD", '', $str->string);
+
+ return $str;
+ }
+
+ public function trimEnd(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): parent
+ {
+ if (" \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}" !== $chars && !preg_match('//u', $chars)) {
+ throw new InvalidArgumentException('Invalid UTF-8 chars.');
+ }
+ $chars = preg_quote($chars);
+
+ $str = clone $this;
+ $str->string = preg_replace("{[$chars]++$}uD", '', $str->string);
+
+ return $str;
+ }
+
+ public function trimPrefix($prefix): parent
+ {
+ if (!$this->ignoreCase) {
+ return parent::trimPrefix($prefix);
+ }
+
+ $str = clone $this;
+
+ if ($prefix instanceof \Traversable) {
+ $prefix = iterator_to_array($prefix, false);
+ } elseif ($prefix instanceof parent) {
+ $prefix = $prefix->string;
+ }
+
+ $prefix = implode('|', array_map('preg_quote', (array) $prefix));
+ $str->string = preg_replace("{^(?:$prefix)}iuD", '', $this->string);
+
+ return $str;
+ }
+
+ public function trimStart(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): parent
+ {
+ if (" \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}" !== $chars && !preg_match('//u', $chars)) {
+ throw new InvalidArgumentException('Invalid UTF-8 chars.');
+ }
+ $chars = preg_quote($chars);
+
+ $str = clone $this;
+ $str->string = preg_replace("{^[$chars]++}uD", '', $str->string);
+
+ return $str;
+ }
+
+ public function trimSuffix($suffix): parent
+ {
+ if (!$this->ignoreCase) {
+ return parent::trimSuffix($suffix);
+ }
+
+ $str = clone $this;
+
+ if ($suffix instanceof \Traversable) {
+ $suffix = iterator_to_array($suffix, false);
+ } elseif ($suffix instanceof parent) {
+ $suffix = $suffix->string;
+ }
+
+ $suffix = implode('|', array_map('preg_quote', (array) $suffix));
+ $str->string = preg_replace("{(?:$suffix)$}iuD", '', $this->string);
+
+ return $str;
+ }
+
+ public function upper(): parent
+ {
+ $str = clone $this;
+ $str->string = mb_strtoupper($str->string, 'UTF-8');
+
+ if (\PHP_VERSION_ID < 70300) {
+ $str->string = str_replace(self::UPPER_FROM, self::UPPER_TO, $str->string);
+ }
+
+ return $str;
+ }
+
+ public function width(bool $ignoreAnsiDecoration = true): int
+ {
+ $width = 0;
+ $s = str_replace(["\x00", "\x05", "\x07"], '', $this->string);
+
+ if (false !== strpos($s, "\r")) {
+ $s = str_replace(["\r\n", "\r"], "\n", $s);
+ }
+
+ if (!$ignoreAnsiDecoration) {
+ $s = preg_replace('/[\p{Cc}\x7F]++/u', '', $s);
+ }
+
+ foreach (explode("\n", $s) as $s) {
+ if ($ignoreAnsiDecoration) {
+ $s = preg_replace('/(?:\x1B(?:
+ \[ [\x30-\x3F]*+ [\x20-\x2F]*+ [\x40-\x7E]
+ | [P\]X^_] .*? \x1B\\\\
+ | [\x41-\x7E]
+ )|[\p{Cc}\x7F]++)/xu', '', $s);
+ }
+
+ $lineWidth = $this->wcswidth($s);
+
+ if ($lineWidth > $width) {
+ $width = $lineWidth;
+ }
+ }
+
+ return $width;
+ }
+
+ /**
+ * @return static
+ */
+ private function pad(int $len, self $pad, int $type): parent
+ {
+ $sLen = $this->length();
+
+ if ($len <= $sLen) {
+ return clone $this;
+ }
+
+ $padLen = $pad->length();
+ $freeLen = $len - $sLen;
+ $len = $freeLen % $padLen;
+
+ switch ($type) {
+ case \STR_PAD_RIGHT:
+ return $this->append(str_repeat($pad->string, intdiv($freeLen, $padLen)).($len ? $pad->slice(0, $len) : ''));
+
+ case \STR_PAD_LEFT:
+ return $this->prepend(str_repeat($pad->string, intdiv($freeLen, $padLen)).($len ? $pad->slice(0, $len) : ''));
+
+ case \STR_PAD_BOTH:
+ $freeLen /= 2;
+
+ $rightLen = ceil($freeLen);
+ $len = $rightLen % $padLen;
+ $str = $this->append(str_repeat($pad->string, intdiv($rightLen, $padLen)).($len ? $pad->slice(0, $len) : ''));
+
+ $leftLen = floor($freeLen);
+ $len = $leftLen % $padLen;
+
+ return $str->prepend(str_repeat($pad->string, intdiv($leftLen, $padLen)).($len ? $pad->slice(0, $len) : ''));
+
+ default:
+ throw new InvalidArgumentException('Invalid padding type.');
+ }
+ }
+
+ /**
+ * Based on https://github.com/jquast/wcwidth, a Python implementation of https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c.
+ */
+ private function wcswidth(string $string): int
+ {
+ $width = 0;
+
+ foreach (preg_split('//u', $string, -1, \PREG_SPLIT_NO_EMPTY) as $c) {
+ $codePoint = mb_ord($c, 'UTF-8');
+
+ if (0 === $codePoint // NULL
+ || 0x034F === $codePoint // COMBINING GRAPHEME JOINER
+ || (0x200B <= $codePoint && 0x200F >= $codePoint) // ZERO WIDTH SPACE to RIGHT-TO-LEFT MARK
+ || 0x2028 === $codePoint // LINE SEPARATOR
+ || 0x2029 === $codePoint // PARAGRAPH SEPARATOR
+ || (0x202A <= $codePoint && 0x202E >= $codePoint) // LEFT-TO-RIGHT EMBEDDING to RIGHT-TO-LEFT OVERRIDE
+ || (0x2060 <= $codePoint && 0x2063 >= $codePoint) // WORD JOINER to INVISIBLE SEPARATOR
+ ) {
+ continue;
+ }
+
+ // Non printable characters
+ if (32 > $codePoint // C0 control characters
+ || (0x07F <= $codePoint && 0x0A0 > $codePoint) // C1 control characters and DEL
+ ) {
+ return -1;
+ }
+
+ if (null === self::$tableZero) {
+ self::$tableZero = require __DIR__.'/Resources/data/wcswidth_table_zero.php';
+ }
+
+ if ($codePoint >= self::$tableZero[0][0] && $codePoint <= self::$tableZero[$ubound = \count(self::$tableZero) - 1][1]) {
+ $lbound = 0;
+ while ($ubound >= $lbound) {
+ $mid = floor(($lbound + $ubound) / 2);
+
+ if ($codePoint > self::$tableZero[$mid][1]) {
+ $lbound = $mid + 1;
+ } elseif ($codePoint < self::$tableZero[$mid][0]) {
+ $ubound = $mid - 1;
+ } else {
+ continue 2;
+ }
+ }
+ }
+
+ if (null === self::$tableWide) {
+ self::$tableWide = require __DIR__.'/Resources/data/wcswidth_table_wide.php';
+ }
+
+ if ($codePoint >= self::$tableWide[0][0] && $codePoint <= self::$tableWide[$ubound = \count(self::$tableWide) - 1][1]) {
+ $lbound = 0;
+ while ($ubound >= $lbound) {
+ $mid = floor(($lbound + $ubound) / 2);
+
+ if ($codePoint > self::$tableWide[$mid][1]) {
+ $lbound = $mid + 1;
+ } elseif ($codePoint < self::$tableWide[$mid][0]) {
+ $ubound = $mid - 1;
+ } else {
+ $width += 2;
+
+ continue 2;
+ }
+ }
+ }
+
+ ++$width;
+ }
+
+ return $width;
+ }
+}
diff --git a/vendor/symfony/string/ByteString.php b/vendor/symfony/string/ByteString.php
new file mode 100644
index 000000000..626d8c1bb
--- /dev/null
+++ b/vendor/symfony/string/ByteString.php
@@ -0,0 +1,509 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\String;
+
+use Symfony\Component\String\Exception\ExceptionInterface;
+use Symfony\Component\String\Exception\InvalidArgumentException;
+use Symfony\Component\String\Exception\RuntimeException;
+
+/**
+ * Represents a binary-safe string of bytes.
+ *
+ * @author Nicolas Grekas
+ * @author Hugo Hamon
+ *
+ * @throws ExceptionInterface
+ */
+class ByteString extends AbstractString
+{
+ private const ALPHABET_ALPHANUMERIC = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
+
+ public function __construct(string $string = '')
+ {
+ $this->string = $string;
+ }
+
+ /*
+ * The following method was derived from code of the Hack Standard Library (v4.40 - 2020-05-03)
+ *
+ * https://github.com/hhvm/hsl/blob/80a42c02f036f72a42f0415e80d6b847f4bf62d5/src/random/private.php#L16
+ *
+ * Code subject to the MIT license (https://github.com/hhvm/hsl/blob/master/LICENSE).
+ *
+ * Copyright (c) 2004-2020, Facebook, Inc. (https://www.facebook.com/)
+ */
+
+ public static function fromRandom(int $length = 16, string $alphabet = null): self
+ {
+ if ($length <= 0) {
+ throw new InvalidArgumentException(sprintf('A strictly positive length is expected, "%d" given.', $length));
+ }
+
+ $alphabet = $alphabet ?? self::ALPHABET_ALPHANUMERIC;
+ $alphabetSize = \strlen($alphabet);
+ $bits = (int) ceil(log($alphabetSize, 2.0));
+ if ($bits <= 0 || $bits > 56) {
+ throw new InvalidArgumentException('The length of the alphabet must in the [2^1, 2^56] range.');
+ }
+
+ $ret = '';
+ while ($length > 0) {
+ $urandomLength = (int) ceil(2 * $length * $bits / 8.0);
+ $data = random_bytes($urandomLength);
+ $unpackedData = 0;
+ $unpackedBits = 0;
+ for ($i = 0; $i < $urandomLength && $length > 0; ++$i) {
+ // Unpack 8 bits
+ $unpackedData = ($unpackedData << 8) | \ord($data[$i]);
+ $unpackedBits += 8;
+
+ // While we have enough bits to select a character from the alphabet, keep
+ // consuming the random data
+ for (; $unpackedBits >= $bits && $length > 0; $unpackedBits -= $bits) {
+ $index = ($unpackedData & ((1 << $bits) - 1));
+ $unpackedData >>= $bits;
+ // Unfortunately, the alphabet size is not necessarily a power of two.
+ // Worst case, it is 2^k + 1, which means we need (k+1) bits and we
+ // have around a 50% chance of missing as k gets larger
+ if ($index < $alphabetSize) {
+ $ret .= $alphabet[$index];
+ --$length;
+ }
+ }
+ }
+ }
+
+ return new static($ret);
+ }
+
+ public function bytesAt(int $offset): array
+ {
+ $str = $this->string[$offset] ?? '';
+
+ return '' === $str ? [] : [\ord($str)];
+ }
+
+ public function append(string ...$suffix): parent
+ {
+ $str = clone $this;
+ $str->string .= 1 >= \count($suffix) ? ($suffix[0] ?? '') : implode('', $suffix);
+
+ return $str;
+ }
+
+ public function camel(): parent
+ {
+ $str = clone $this;
+
+ $parts = explode(' ', trim(ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $this->string))));
+ $parts[0] = 1 !== \strlen($parts[0]) && ctype_upper($parts[0]) ? $parts[0] : lcfirst($parts[0]);
+ $str->string = implode('', $parts);
+
+ return $str;
+ }
+
+ public function chunk(int $length = 1): array
+ {
+ if (1 > $length) {
+ throw new InvalidArgumentException('The chunk length must be greater than zero.');
+ }
+
+ if ('' === $this->string) {
+ return [];
+ }
+
+ $str = clone $this;
+ $chunks = [];
+
+ foreach (str_split($this->string, $length) as $chunk) {
+ $str->string = $chunk;
+ $chunks[] = clone $str;
+ }
+
+ return $chunks;
+ }
+
+ public function endsWith($suffix): bool
+ {
+ if ($suffix instanceof parent) {
+ $suffix = $suffix->string;
+ } elseif (\is_array($suffix) || $suffix instanceof \Traversable) {
+ return parent::endsWith($suffix);
+ } else {
+ $suffix = (string) $suffix;
+ }
+
+ return '' !== $suffix && \strlen($this->string) >= \strlen($suffix) && 0 === substr_compare($this->string, $suffix, -\strlen($suffix), null, $this->ignoreCase);
+ }
+
+ public function equalsTo($string): bool
+ {
+ if ($string instanceof parent) {
+ $string = $string->string;
+ } elseif (\is_array($string) || $string instanceof \Traversable) {
+ return parent::equalsTo($string);
+ } else {
+ $string = (string) $string;
+ }
+
+ if ('' !== $string && $this->ignoreCase) {
+ return 0 === strcasecmp($string, $this->string);
+ }
+
+ return $string === $this->string;
+ }
+
+ public function folded(): parent
+ {
+ $str = clone $this;
+ $str->string = strtolower($str->string);
+
+ return $str;
+ }
+
+ public function indexOf($needle, int $offset = 0): ?int
+ {
+ if ($needle instanceof parent) {
+ $needle = $needle->string;
+ } elseif (\is_array($needle) || $needle instanceof \Traversable) {
+ return parent::indexOf($needle, $offset);
+ } else {
+ $needle = (string) $needle;
+ }
+
+ if ('' === $needle) {
+ return null;
+ }
+
+ $i = $this->ignoreCase ? stripos($this->string, $needle, $offset) : strpos($this->string, $needle, $offset);
+
+ return false === $i ? null : $i;
+ }
+
+ public function indexOfLast($needle, int $offset = 0): ?int
+ {
+ if ($needle instanceof parent) {
+ $needle = $needle->string;
+ } elseif (\is_array($needle) || $needle instanceof \Traversable) {
+ return parent::indexOfLast($needle, $offset);
+ } else {
+ $needle = (string) $needle;
+ }
+
+ if ('' === $needle) {
+ return null;
+ }
+
+ $i = $this->ignoreCase ? strripos($this->string, $needle, $offset) : strrpos($this->string, $needle, $offset);
+
+ return false === $i ? null : $i;
+ }
+
+ public function isUtf8(): bool
+ {
+ return '' === $this->string || preg_match('//u', $this->string);
+ }
+
+ public function join(array $strings, string $lastGlue = null): parent
+ {
+ $str = clone $this;
+
+ $tail = null !== $lastGlue && 1 < \count($strings) ? $lastGlue.array_pop($strings) : '';
+ $str->string = implode($this->string, $strings).$tail;
+
+ return $str;
+ }
+
+ public function length(): int
+ {
+ return \strlen($this->string);
+ }
+
+ public function lower(): parent
+ {
+ $str = clone $this;
+ $str->string = strtolower($str->string);
+
+ return $str;
+ }
+
+ public function match(string $regexp, int $flags = 0, int $offset = 0): array
+ {
+ $match = ((\PREG_PATTERN_ORDER | \PREG_SET_ORDER) & $flags) ? 'preg_match_all' : 'preg_match';
+
+ if ($this->ignoreCase) {
+ $regexp .= 'i';
+ }
+
+ set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); });
+
+ try {
+ if (false === $match($regexp, $this->string, $matches, $flags | \PREG_UNMATCHED_AS_NULL, $offset)) {
+ $lastError = preg_last_error();
+
+ foreach (get_defined_constants(true)['pcre'] as $k => $v) {
+ if ($lastError === $v && '_ERROR' === substr($k, -6)) {
+ throw new RuntimeException('Matching failed with '.$k.'.');
+ }
+ }
+
+ throw new RuntimeException('Matching failed with unknown error code.');
+ }
+ } finally {
+ restore_error_handler();
+ }
+
+ return $matches;
+ }
+
+ public function padBoth(int $length, string $padStr = ' '): parent
+ {
+ $str = clone $this;
+ $str->string = str_pad($this->string, $length, $padStr, \STR_PAD_BOTH);
+
+ return $str;
+ }
+
+ public function padEnd(int $length, string $padStr = ' '): parent
+ {
+ $str = clone $this;
+ $str->string = str_pad($this->string, $length, $padStr, \STR_PAD_RIGHT);
+
+ return $str;
+ }
+
+ public function padStart(int $length, string $padStr = ' '): parent
+ {
+ $str = clone $this;
+ $str->string = str_pad($this->string, $length, $padStr, \STR_PAD_LEFT);
+
+ return $str;
+ }
+
+ public function prepend(string ...$prefix): parent
+ {
+ $str = clone $this;
+ $str->string = (1 >= \count($prefix) ? ($prefix[0] ?? '') : implode('', $prefix)).$str->string;
+
+ return $str;
+ }
+
+ public function replace(string $from, string $to): parent
+ {
+ $str = clone $this;
+
+ if ('' !== $from) {
+ $str->string = $this->ignoreCase ? str_ireplace($from, $to, $this->string) : str_replace($from, $to, $this->string);
+ }
+
+ return $str;
+ }
+
+ public function replaceMatches(string $fromRegexp, $to): parent
+ {
+ if ($this->ignoreCase) {
+ $fromRegexp .= 'i';
+ }
+
+ if (\is_array($to)) {
+ if (!\is_callable($to)) {
+ throw new \TypeError(sprintf('Argument 2 passed to "%s::replaceMatches()" must be callable, array given.', static::class));
+ }
+
+ $replace = 'preg_replace_callback';
+ } else {
+ $replace = $to instanceof \Closure ? 'preg_replace_callback' : 'preg_replace';
+ }
+
+ set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); });
+
+ try {
+ if (null === $string = $replace($fromRegexp, $to, $this->string)) {
+ $lastError = preg_last_error();
+
+ foreach (get_defined_constants(true)['pcre'] as $k => $v) {
+ if ($lastError === $v && '_ERROR' === substr($k, -6)) {
+ throw new RuntimeException('Matching failed with '.$k.'.');
+ }
+ }
+
+ throw new RuntimeException('Matching failed with unknown error code.');
+ }
+ } finally {
+ restore_error_handler();
+ }
+
+ $str = clone $this;
+ $str->string = $string;
+
+ return $str;
+ }
+
+ public function reverse(): parent
+ {
+ $str = clone $this;
+ $str->string = strrev($str->string);
+
+ return $str;
+ }
+
+ public function slice(int $start = 0, int $length = null): parent
+ {
+ $str = clone $this;
+ $str->string = (string) substr($this->string, $start, $length ?? \PHP_INT_MAX);
+
+ return $str;
+ }
+
+ public function snake(): parent
+ {
+ $str = $this->camel();
+ $str->string = strtolower(preg_replace(['/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'], '\1_\2', $str->string));
+
+ return $str;
+ }
+
+ public function splice(string $replacement, int $start = 0, int $length = null): parent
+ {
+ $str = clone $this;
+ $str->string = substr_replace($this->string, $replacement, $start, $length ?? \PHP_INT_MAX);
+
+ return $str;
+ }
+
+ public function split(string $delimiter, int $limit = null, int $flags = null): array
+ {
+ if (1 > $limit = $limit ?? \PHP_INT_MAX) {
+ throw new InvalidArgumentException('Split limit must be a positive integer.');
+ }
+
+ if ('' === $delimiter) {
+ throw new InvalidArgumentException('Split delimiter is empty.');
+ }
+
+ if (null !== $flags) {
+ return parent::split($delimiter, $limit, $flags);
+ }
+
+ $str = clone $this;
+ $chunks = $this->ignoreCase
+ ? preg_split('{'.preg_quote($delimiter).'}iD', $this->string, $limit)
+ : explode($delimiter, $this->string, $limit);
+
+ foreach ($chunks as &$chunk) {
+ $str->string = $chunk;
+ $chunk = clone $str;
+ }
+
+ return $chunks;
+ }
+
+ public function startsWith($prefix): bool
+ {
+ if ($prefix instanceof parent) {
+ $prefix = $prefix->string;
+ } elseif (!\is_string($prefix)) {
+ return parent::startsWith($prefix);
+ }
+
+ return '' !== $prefix && 0 === ($this->ignoreCase ? strncasecmp($this->string, $prefix, \strlen($prefix)) : strncmp($this->string, $prefix, \strlen($prefix)));
+ }
+
+ public function title(bool $allWords = false): parent
+ {
+ $str = clone $this;
+ $str->string = $allWords ? ucwords($str->string) : ucfirst($str->string);
+
+ return $str;
+ }
+
+ public function toUnicodeString(string $fromEncoding = null): UnicodeString
+ {
+ return new UnicodeString($this->toCodePointString($fromEncoding)->string);
+ }
+
+ public function toCodePointString(string $fromEncoding = null): CodePointString
+ {
+ $u = new CodePointString();
+
+ if (\in_array($fromEncoding, [null, 'utf8', 'utf-8', 'UTF8', 'UTF-8'], true) && preg_match('//u', $this->string)) {
+ $u->string = $this->string;
+
+ return $u;
+ }
+
+ set_error_handler(static function ($t, $m) { throw new InvalidArgumentException($m); });
+
+ try {
+ try {
+ $validEncoding = false !== mb_detect_encoding($this->string, $fromEncoding ?? 'Windows-1252', true);
+ } catch (InvalidArgumentException $e) {
+ if (!\function_exists('iconv')) {
+ throw $e;
+ }
+
+ $u->string = iconv($fromEncoding ?? 'Windows-1252', 'UTF-8', $this->string);
+
+ return $u;
+ }
+ } finally {
+ restore_error_handler();
+ }
+
+ if (!$validEncoding) {
+ throw new InvalidArgumentException(sprintf('Invalid "%s" string.', $fromEncoding ?? 'Windows-1252'));
+ }
+
+ $u->string = mb_convert_encoding($this->string, 'UTF-8', $fromEncoding ?? 'Windows-1252');
+
+ return $u;
+ }
+
+ public function trim(string $chars = " \t\n\r\0\x0B\x0C"): parent
+ {
+ $str = clone $this;
+ $str->string = trim($str->string, $chars);
+
+ return $str;
+ }
+
+ public function trimEnd(string $chars = " \t\n\r\0\x0B\x0C"): parent
+ {
+ $str = clone $this;
+ $str->string = rtrim($str->string, $chars);
+
+ return $str;
+ }
+
+ public function trimStart(string $chars = " \t\n\r\0\x0B\x0C"): parent
+ {
+ $str = clone $this;
+ $str->string = ltrim($str->string, $chars);
+
+ return $str;
+ }
+
+ public function upper(): parent
+ {
+ $str = clone $this;
+ $str->string = strtoupper($str->string);
+
+ return $str;
+ }
+
+ public function width(bool $ignoreAnsiDecoration = true): int
+ {
+ $string = preg_match('//u', $this->string) ? $this->string : preg_replace('/[\x80-\xFF]/', '?', $this->string);
+
+ return (new CodePointString($string))->width($ignoreAnsiDecoration);
+ }
+}
diff --git a/vendor/symfony/string/CHANGELOG.md b/vendor/symfony/string/CHANGELOG.md
new file mode 100644
index 000000000..53af36400
--- /dev/null
+++ b/vendor/symfony/string/CHANGELOG.md
@@ -0,0 +1,35 @@
+CHANGELOG
+=========
+
+5.4
+---
+
+ * Add `trimSuffix()` and `trimPrefix()` methods
+
+5.3
+---
+
+ * Made `AsciiSlugger` fallback to parent locale's symbolsMap
+
+5.2.0
+-----
+
+ * added a `FrenchInflector` class
+
+5.1.0
+-----
+
+ * added the `AbstractString::reverse()` method
+ * made `AbstractString::width()` follow POSIX.1-2001
+ * added `LazyString` which provides memoizing stringable objects
+ * The component is not marked as `@experimental` anymore
+ * added the `s()` helper method to get either an `UnicodeString` or `ByteString` instance,
+ depending of the input string UTF-8 compliancy
+ * added `$cut` parameter to `Symfony\Component\String\AbstractString::truncate()`
+ * added `AbstractString::containsAny()`
+ * allow passing a string of custom characters to `ByteString::fromRandom()`
+
+5.0.0
+-----
+
+ * added the component as experimental
diff --git a/vendor/symfony/string/CodePointString.php b/vendor/symfony/string/CodePointString.php
new file mode 100644
index 000000000..8ab920941
--- /dev/null
+++ b/vendor/symfony/string/CodePointString.php
@@ -0,0 +1,270 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\String;
+
+use Symfony\Component\String\Exception\ExceptionInterface;
+use Symfony\Component\String\Exception\InvalidArgumentException;
+
+/**
+ * Represents a string of Unicode code points encoded as UTF-8.
+ *
+ * @author Nicolas Grekas
+ * @author Hugo Hamon
+ *
+ * @throws ExceptionInterface
+ */
+class CodePointString extends AbstractUnicodeString
+{
+ public function __construct(string $string = '')
+ {
+ if ('' !== $string && !preg_match('//u', $string)) {
+ throw new InvalidArgumentException('Invalid UTF-8 string.');
+ }
+
+ $this->string = $string;
+ }
+
+ public function append(string ...$suffix): AbstractString
+ {
+ $str = clone $this;
+ $str->string .= 1 >= \count($suffix) ? ($suffix[0] ?? '') : implode('', $suffix);
+
+ if (!preg_match('//u', $str->string)) {
+ throw new InvalidArgumentException('Invalid UTF-8 string.');
+ }
+
+ return $str;
+ }
+
+ public function chunk(int $length = 1): array
+ {
+ if (1 > $length) {
+ throw new InvalidArgumentException('The chunk length must be greater than zero.');
+ }
+
+ if ('' === $this->string) {
+ return [];
+ }
+
+ $rx = '/(';
+ while (65535 < $length) {
+ $rx .= '.{65535}';
+ $length -= 65535;
+ }
+ $rx .= '.{'.$length.'})/us';
+
+ $str = clone $this;
+ $chunks = [];
+
+ foreach (preg_split($rx, $this->string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY) as $chunk) {
+ $str->string = $chunk;
+ $chunks[] = clone $str;
+ }
+
+ return $chunks;
+ }
+
+ public function codePointsAt(int $offset): array
+ {
+ $str = $offset ? $this->slice($offset, 1) : $this;
+
+ return '' === $str->string ? [] : [mb_ord($str->string, 'UTF-8')];
+ }
+
+ public function endsWith($suffix): bool
+ {
+ if ($suffix instanceof AbstractString) {
+ $suffix = $suffix->string;
+ } elseif (\is_array($suffix) || $suffix instanceof \Traversable) {
+ return parent::endsWith($suffix);
+ } else {
+ $suffix = (string) $suffix;
+ }
+
+ if ('' === $suffix || !preg_match('//u', $suffix)) {
+ return false;
+ }
+
+ if ($this->ignoreCase) {
+ return preg_match('{'.preg_quote($suffix).'$}iuD', $this->string);
+ }
+
+ return \strlen($this->string) >= \strlen($suffix) && 0 === substr_compare($this->string, $suffix, -\strlen($suffix));
+ }
+
+ public function equalsTo($string): bool
+ {
+ if ($string instanceof AbstractString) {
+ $string = $string->string;
+ } elseif (\is_array($string) || $string instanceof \Traversable) {
+ return parent::equalsTo($string);
+ } else {
+ $string = (string) $string;
+ }
+
+ if ('' !== $string && $this->ignoreCase) {
+ return \strlen($string) === \strlen($this->string) && 0 === mb_stripos($this->string, $string, 0, 'UTF-8');
+ }
+
+ return $string === $this->string;
+ }
+
+ public function indexOf($needle, int $offset = 0): ?int
+ {
+ if ($needle instanceof AbstractString) {
+ $needle = $needle->string;
+ } elseif (\is_array($needle) || $needle instanceof \Traversable) {
+ return parent::indexOf($needle, $offset);
+ } else {
+ $needle = (string) $needle;
+ }
+
+ if ('' === $needle) {
+ return null;
+ }
+
+ $i = $this->ignoreCase ? mb_stripos($this->string, $needle, $offset, 'UTF-8') : mb_strpos($this->string, $needle, $offset, 'UTF-8');
+
+ return false === $i ? null : $i;
+ }
+
+ public function indexOfLast($needle, int $offset = 0): ?int
+ {
+ if ($needle instanceof AbstractString) {
+ $needle = $needle->string;
+ } elseif (\is_array($needle) || $needle instanceof \Traversable) {
+ return parent::indexOfLast($needle, $offset);
+ } else {
+ $needle = (string) $needle;
+ }
+
+ if ('' === $needle) {
+ return null;
+ }
+
+ $i = $this->ignoreCase ? mb_strripos($this->string, $needle, $offset, 'UTF-8') : mb_strrpos($this->string, $needle, $offset, 'UTF-8');
+
+ return false === $i ? null : $i;
+ }
+
+ public function length(): int
+ {
+ return mb_strlen($this->string, 'UTF-8');
+ }
+
+ public function prepend(string ...$prefix): AbstractString
+ {
+ $str = clone $this;
+ $str->string = (1 >= \count($prefix) ? ($prefix[0] ?? '') : implode('', $prefix)).$this->string;
+
+ if (!preg_match('//u', $str->string)) {
+ throw new InvalidArgumentException('Invalid UTF-8 string.');
+ }
+
+ return $str;
+ }
+
+ public function replace(string $from, string $to): AbstractString
+ {
+ $str = clone $this;
+
+ if ('' === $from || !preg_match('//u', $from)) {
+ return $str;
+ }
+
+ if ('' !== $to && !preg_match('//u', $to)) {
+ throw new InvalidArgumentException('Invalid UTF-8 string.');
+ }
+
+ if ($this->ignoreCase) {
+ $str->string = implode($to, preg_split('{'.preg_quote($from).'}iuD', $this->string));
+ } else {
+ $str->string = str_replace($from, $to, $this->string);
+ }
+
+ return $str;
+ }
+
+ public function slice(int $start = 0, int $length = null): AbstractString
+ {
+ $str = clone $this;
+ $str->string = mb_substr($this->string, $start, $length, 'UTF-8');
+
+ return $str;
+ }
+
+ public function splice(string $replacement, int $start = 0, int $length = null): AbstractString
+ {
+ if (!preg_match('//u', $replacement)) {
+ throw new InvalidArgumentException('Invalid UTF-8 string.');
+ }
+
+ $str = clone $this;
+ $start = $start ? \strlen(mb_substr($this->string, 0, $start, 'UTF-8')) : 0;
+ $length = $length ? \strlen(mb_substr($this->string, $start, $length, 'UTF-8')) : $length;
+ $str->string = substr_replace($this->string, $replacement, $start, $length ?? \PHP_INT_MAX);
+
+ return $str;
+ }
+
+ public function split(string $delimiter, int $limit = null, int $flags = null): array
+ {
+ if (1 > $limit = $limit ?? \PHP_INT_MAX) {
+ throw new InvalidArgumentException('Split limit must be a positive integer.');
+ }
+
+ if ('' === $delimiter) {
+ throw new InvalidArgumentException('Split delimiter is empty.');
+ }
+
+ if (null !== $flags) {
+ return parent::split($delimiter.'u', $limit, $flags);
+ }
+
+ if (!preg_match('//u', $delimiter)) {
+ throw new InvalidArgumentException('Split delimiter is not a valid UTF-8 string.');
+ }
+
+ $str = clone $this;
+ $chunks = $this->ignoreCase
+ ? preg_split('{'.preg_quote($delimiter).'}iuD', $this->string, $limit)
+ : explode($delimiter, $this->string, $limit);
+
+ foreach ($chunks as &$chunk) {
+ $str->string = $chunk;
+ $chunk = clone $str;
+ }
+
+ return $chunks;
+ }
+
+ public function startsWith($prefix): bool
+ {
+ if ($prefix instanceof AbstractString) {
+ $prefix = $prefix->string;
+ } elseif (\is_array($prefix) || $prefix instanceof \Traversable) {
+ return parent::startsWith($prefix);
+ } else {
+ $prefix = (string) $prefix;
+ }
+
+ if ('' === $prefix || !preg_match('//u', $prefix)) {
+ return false;
+ }
+
+ if ($this->ignoreCase) {
+ return 0 === mb_stripos($this->string, $prefix, 0, 'UTF-8');
+ }
+
+ return 0 === strncmp($this->string, $prefix, \strlen($prefix));
+ }
+}
diff --git a/vendor/symfony/string/Exception/ExceptionInterface.php b/vendor/symfony/string/Exception/ExceptionInterface.php
new file mode 100644
index 000000000..361978656
--- /dev/null
+++ b/vendor/symfony/string/Exception/ExceptionInterface.php
@@ -0,0 +1,16 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\String\Exception;
+
+interface ExceptionInterface extends \Throwable
+{
+}
diff --git a/vendor/symfony/string/Exception/InvalidArgumentException.php b/vendor/symfony/string/Exception/InvalidArgumentException.php
new file mode 100644
index 000000000..6aa586bcf
--- /dev/null
+++ b/vendor/symfony/string/Exception/InvalidArgumentException.php
@@ -0,0 +1,16 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\String\Exception;
+
+class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
+{
+}
diff --git a/vendor/symfony/string/Exception/RuntimeException.php b/vendor/symfony/string/Exception/RuntimeException.php
new file mode 100644
index 000000000..77cb091f9
--- /dev/null
+++ b/vendor/symfony/string/Exception/RuntimeException.php
@@ -0,0 +1,16 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\String\Exception;
+
+class RuntimeException extends \RuntimeException implements ExceptionInterface
+{
+}
diff --git a/vendor/symfony/string/Inflector/EnglishInflector.php b/vendor/symfony/string/Inflector/EnglishInflector.php
new file mode 100644
index 000000000..edd94dbc1
--- /dev/null
+++ b/vendor/symfony/string/Inflector/EnglishInflector.php
@@ -0,0 +1,517 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\String\Inflector;
+
+final class EnglishInflector implements InflectorInterface
+{
+ /**
+ * Map English plural to singular suffixes.
+ *
+ * @see http://english-zone.com/spelling/plurals.html
+ */
+ private const PLURAL_MAP = [
+ // First entry: plural suffix, reversed
+ // Second entry: length of plural suffix
+ // Third entry: Whether the suffix may succeed a vocal
+ // Fourth entry: Whether the suffix may succeed a consonant
+ // Fifth entry: singular suffix, normal
+
+ // bacteria (bacterium), criteria (criterion), phenomena (phenomenon)
+ ['a', 1, true, true, ['on', 'um']],
+
+ // nebulae (nebula)
+ ['ea', 2, true, true, 'a'],
+
+ // services (service)
+ ['secivres', 8, true, true, 'service'],
+
+ // mice (mouse), lice (louse)
+ ['eci', 3, false, true, 'ouse'],
+
+ // geese (goose)
+ ['esee', 4, false, true, 'oose'],
+
+ // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius)
+ ['i', 1, true, true, 'us'],
+
+ // men (man), women (woman)
+ ['nem', 3, true, true, 'man'],
+
+ // children (child)
+ ['nerdlihc', 8, true, true, 'child'],
+
+ // oxen (ox)
+ ['nexo', 4, false, false, 'ox'],
+
+ // indices (index), appendices (appendix), prices (price)
+ ['seci', 4, false, true, ['ex', 'ix', 'ice']],
+
+ // codes (code)
+ ['sedoc', 5, false, true, 'code'],
+
+ // selfies (selfie)
+ ['seifles', 7, true, true, 'selfie'],
+
+ // zombies (zombie)
+ ['seibmoz', 7, true, true, 'zombie'],
+
+ // movies (movie)
+ ['seivom', 6, true, true, 'movie'],
+
+ // names (name)
+ ['seman', 5, true, false, 'name'],
+
+ // conspectuses (conspectus), prospectuses (prospectus)
+ ['sesutcep', 8, true, true, 'pectus'],
+
+ // feet (foot)
+ ['teef', 4, true, true, 'foot'],
+
+ // geese (goose)
+ ['eseeg', 5, true, true, 'goose'],
+
+ // teeth (tooth)
+ ['hteet', 5, true, true, 'tooth'],
+
+ // news (news)
+ ['swen', 4, true, true, 'news'],
+
+ // series (series)
+ ['seires', 6, true, true, 'series'],
+
+ // babies (baby)
+ ['sei', 3, false, true, 'y'],
+
+ // accesses (access), addresses (address), kisses (kiss)
+ ['sess', 4, true, false, 'ss'],
+
+ // analyses (analysis), ellipses (ellipsis), fungi (fungus),
+ // neuroses (neurosis), theses (thesis), emphases (emphasis),
+ // oases (oasis), crises (crisis), houses (house), bases (base),
+ // atlases (atlas)
+ ['ses', 3, true, true, ['s', 'se', 'sis']],
+
+ // objectives (objective), alternative (alternatives)
+ ['sevit', 5, true, true, 'tive'],
+
+ // drives (drive)
+ ['sevird', 6, false, true, 'drive'],
+
+ // lives (life), wives (wife)
+ ['sevi', 4, false, true, 'ife'],
+
+ // moves (move)
+ ['sevom', 5, true, true, 'move'],
+
+ // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf), caves (cave), staves (staff)
+ ['sev', 3, true, true, ['f', 've', 'ff']],
+
+ // axes (axis), axes (ax), axes (axe)
+ ['sexa', 4, false, false, ['ax', 'axe', 'axis']],
+
+ // indexes (index), matrixes (matrix)
+ ['sex', 3, true, false, 'x'],
+
+ // quizzes (quiz)
+ ['sezz', 4, true, false, 'z'],
+
+ // bureaus (bureau)
+ ['suae', 4, false, true, 'eau'],
+
+ // fees (fee), trees (tree), employees (employee)
+ ['see', 3, true, true, 'ee'],
+
+ // edges (edge)
+ ['segd', 4, true, true, 'dge'],
+
+ // roses (rose), garages (garage), cassettes (cassette),
+ // waltzes (waltz), heroes (hero), bushes (bush), arches (arch),
+ // shoes (shoe)
+ ['se', 2, true, true, ['', 'e']],
+
+ // tags (tag)
+ ['s', 1, true, true, ''],
+
+ // chateaux (chateau)
+ ['xuae', 4, false, true, 'eau'],
+
+ // people (person)
+ ['elpoep', 6, true, true, 'person'],
+ ];
+
+ /**
+ * Map English singular to plural suffixes.
+ *
+ * @see http://english-zone.com/spelling/plurals.html
+ */
+ private const SINGULAR_MAP = [
+ // First entry: singular suffix, reversed
+ // Second entry: length of singular suffix
+ // Third entry: Whether the suffix may succeed a vocal
+ // Fourth entry: Whether the suffix may succeed a consonant
+ // Fifth entry: plural suffix, normal
+
+ // criterion (criteria)
+ ['airetirc', 8, false, false, 'criterion'],
+
+ // nebulae (nebula)
+ ['aluben', 6, false, false, 'nebulae'],
+
+ // children (child)
+ ['dlihc', 5, true, true, 'children'],
+
+ // prices (price)
+ ['eci', 3, false, true, 'ices'],
+
+ // services (service)
+ ['ecivres', 7, true, true, 'services'],
+
+ // lives (life), wives (wife)
+ ['efi', 3, false, true, 'ives'],
+
+ // selfies (selfie)
+ ['eifles', 6, true, true, 'selfies'],
+
+ // movies (movie)
+ ['eivom', 5, true, true, 'movies'],
+
+ // lice (louse)
+ ['esuol', 5, false, true, 'lice'],
+
+ // mice (mouse)
+ ['esuom', 5, false, true, 'mice'],
+
+ // geese (goose)
+ ['esoo', 4, false, true, 'eese'],
+
+ // houses (house), bases (base)
+ ['es', 2, true, true, 'ses'],
+
+ // geese (goose)
+ ['esoog', 5, true, true, 'geese'],
+
+ // caves (cave)
+ ['ev', 2, true, true, 'ves'],
+
+ // drives (drive)
+ ['evird', 5, false, true, 'drives'],
+
+ // objectives (objective), alternative (alternatives)
+ ['evit', 4, true, true, 'tives'],
+
+ // moves (move)
+ ['evom', 4, true, true, 'moves'],
+
+ // staves (staff)
+ ['ffats', 5, true, true, 'staves'],
+
+ // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf)
+ ['ff', 2, true, true, 'ffs'],
+
+ // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf)
+ ['f', 1, true, true, ['fs', 'ves']],
+
+ // arches (arch)
+ ['hc', 2, true, true, 'ches'],
+
+ // bushes (bush)
+ ['hs', 2, true, true, 'shes'],
+
+ // teeth (tooth)
+ ['htoot', 5, true, true, 'teeth'],
+
+ // bacteria (bacterium), criteria (criterion), phenomena (phenomenon)
+ ['mu', 2, true, true, 'a'],
+
+ // men (man), women (woman)
+ ['nam', 3, true, true, 'men'],
+
+ // people (person)
+ ['nosrep', 6, true, true, ['persons', 'people']],
+
+ // bacteria (bacterium), criteria (criterion), phenomena (phenomenon)
+ ['noi', 3, true, true, 'ions'],
+
+ // coupon (coupons)
+ ['nop', 3, true, true, 'pons'],
+
+ // seasons (season), treasons (treason), poisons (poison), lessons (lesson)
+ ['nos', 3, true, true, 'sons'],
+
+ // bacteria (bacterium), criteria (criterion), phenomena (phenomenon)
+ ['no', 2, true, true, 'a'],
+
+ // echoes (echo)
+ ['ohce', 4, true, true, 'echoes'],
+
+ // heroes (hero)
+ ['oreh', 4, true, true, 'heroes'],
+
+ // atlases (atlas)
+ ['salta', 5, true, true, 'atlases'],
+
+ // irises (iris)
+ ['siri', 4, true, true, 'irises'],
+
+ // analyses (analysis), ellipses (ellipsis), neuroses (neurosis)
+ // theses (thesis), emphases (emphasis), oases (oasis),
+ // crises (crisis)
+ ['sis', 3, true, true, 'ses'],
+
+ // accesses (access), addresses (address), kisses (kiss)
+ ['ss', 2, true, false, 'sses'],
+
+ // syllabi (syllabus)
+ ['suballys', 8, true, true, 'syllabi'],
+
+ // buses (bus)
+ ['sub', 3, true, true, 'buses'],
+
+ // circuses (circus)
+ ['suc', 3, true, true, 'cuses'],
+
+ // conspectuses (conspectus), prospectuses (prospectus)
+ ['sutcep', 6, true, true, 'pectuses'],
+
+ // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius)
+ ['su', 2, true, true, 'i'],
+
+ // news (news)
+ ['swen', 4, true, true, 'news'],
+
+ // feet (foot)
+ ['toof', 4, true, true, 'feet'],
+
+ // chateaux (chateau), bureaus (bureau)
+ ['uae', 3, false, true, ['eaus', 'eaux']],
+
+ // oxen (ox)
+ ['xo', 2, false, false, 'oxen'],
+
+ // hoaxes (hoax)
+ ['xaoh', 4, true, false, 'hoaxes'],
+
+ // indices (index)
+ ['xedni', 5, false, true, ['indicies', 'indexes']],
+
+ // boxes (box)
+ ['xo', 2, false, true, 'oxes'],
+
+ // indexes (index), matrixes (matrix)
+ ['x', 1, true, false, ['cies', 'xes']],
+
+ // appendices (appendix)
+ ['xi', 2, false, true, 'ices'],
+
+ // babies (baby)
+ ['y', 1, false, true, 'ies'],
+
+ // quizzes (quiz)
+ ['ziuq', 4, true, false, 'quizzes'],
+
+ // waltzes (waltz)
+ ['z', 1, true, true, 'zes'],
+ ];
+
+ /**
+ * A list of words which should not be inflected, reversed.
+ */
+ private const UNINFLECTED = [
+ '',
+
+ // data
+ 'atad',
+
+ // deer
+ 'reed',
+
+ // feedback
+ 'kcabdeef',
+
+ // fish
+ 'hsif',
+
+ // info
+ 'ofni',
+
+ // moose
+ 'esoom',
+
+ // series
+ 'seires',
+
+ // sheep
+ 'peehs',
+
+ // species
+ 'seiceps',
+ ];
+
+ /**
+ * {@inheritdoc}
+ */
+ public function singularize(string $plural): array
+ {
+ $pluralRev = strrev($plural);
+ $lowerPluralRev = strtolower($pluralRev);
+ $pluralLength = \strlen($lowerPluralRev);
+
+ // Check if the word is one which is not inflected, return early if so
+ if (\in_array($lowerPluralRev, self::UNINFLECTED, true)) {
+ return [$plural];
+ }
+
+ // The outer loop iterates over the entries of the plural table
+ // The inner loop $j iterates over the characters of the plural suffix
+ // in the plural table to compare them with the characters of the actual
+ // given plural suffix
+ foreach (self::PLURAL_MAP as $map) {
+ $suffix = $map[0];
+ $suffixLength = $map[1];
+ $j = 0;
+
+ // Compare characters in the plural table and of the suffix of the
+ // given plural one by one
+ while ($suffix[$j] === $lowerPluralRev[$j]) {
+ // Let $j point to the next character
+ ++$j;
+
+ // Successfully compared the last character
+ // Add an entry with the singular suffix to the singular array
+ if ($j === $suffixLength) {
+ // Is there any character preceding the suffix in the plural string?
+ if ($j < $pluralLength) {
+ $nextIsVocal = false !== strpos('aeiou', $lowerPluralRev[$j]);
+
+ if (!$map[2] && $nextIsVocal) {
+ // suffix may not succeed a vocal but next char is one
+ break;
+ }
+
+ if (!$map[3] && !$nextIsVocal) {
+ // suffix may not succeed a consonant but next char is one
+ break;
+ }
+ }
+
+ $newBase = substr($plural, 0, $pluralLength - $suffixLength);
+ $newSuffix = $map[4];
+
+ // Check whether the first character in the plural suffix
+ // is uppercased. If yes, uppercase the first character in
+ // the singular suffix too
+ $firstUpper = ctype_upper($pluralRev[$j - 1]);
+
+ if (\is_array($newSuffix)) {
+ $singulars = [];
+
+ foreach ($newSuffix as $newSuffixEntry) {
+ $singulars[] = $newBase.($firstUpper ? ucfirst($newSuffixEntry) : $newSuffixEntry);
+ }
+
+ return $singulars;
+ }
+
+ return [$newBase.($firstUpper ? ucfirst($newSuffix) : $newSuffix)];
+ }
+
+ // Suffix is longer than word
+ if ($j === $pluralLength) {
+ break;
+ }
+ }
+ }
+
+ // Assume that plural and singular is identical
+ return [$plural];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function pluralize(string $singular): array
+ {
+ $singularRev = strrev($singular);
+ $lowerSingularRev = strtolower($singularRev);
+ $singularLength = \strlen($lowerSingularRev);
+
+ // Check if the word is one which is not inflected, return early if so
+ if (\in_array($lowerSingularRev, self::UNINFLECTED, true)) {
+ return [$singular];
+ }
+
+ // The outer loop iterates over the entries of the singular table
+ // The inner loop $j iterates over the characters of the singular suffix
+ // in the singular table to compare them with the characters of the actual
+ // given singular suffix
+ foreach (self::SINGULAR_MAP as $map) {
+ $suffix = $map[0];
+ $suffixLength = $map[1];
+ $j = 0;
+
+ // Compare characters in the singular table and of the suffix of the
+ // given plural one by one
+
+ while ($suffix[$j] === $lowerSingularRev[$j]) {
+ // Let $j point to the next character
+ ++$j;
+
+ // Successfully compared the last character
+ // Add an entry with the plural suffix to the plural array
+ if ($j === $suffixLength) {
+ // Is there any character preceding the suffix in the plural string?
+ if ($j < $singularLength) {
+ $nextIsVocal = false !== strpos('aeiou', $lowerSingularRev[$j]);
+
+ if (!$map[2] && $nextIsVocal) {
+ // suffix may not succeed a vocal but next char is one
+ break;
+ }
+
+ if (!$map[3] && !$nextIsVocal) {
+ // suffix may not succeed a consonant but next char is one
+ break;
+ }
+ }
+
+ $newBase = substr($singular, 0, $singularLength - $suffixLength);
+ $newSuffix = $map[4];
+
+ // Check whether the first character in the singular suffix
+ // is uppercased. If yes, uppercase the first character in
+ // the singular suffix too
+ $firstUpper = ctype_upper($singularRev[$j - 1]);
+
+ if (\is_array($newSuffix)) {
+ $plurals = [];
+
+ foreach ($newSuffix as $newSuffixEntry) {
+ $plurals[] = $newBase.($firstUpper ? ucfirst($newSuffixEntry) : $newSuffixEntry);
+ }
+
+ return $plurals;
+ }
+
+ return [$newBase.($firstUpper ? ucfirst($newSuffix) : $newSuffix)];
+ }
+
+ // Suffix is longer than word
+ if ($j === $singularLength) {
+ break;
+ }
+ }
+ }
+
+ // Assume that plural is singular with a trailing `s`
+ return [$singular.'s'];
+ }
+}
diff --git a/vendor/symfony/string/Inflector/FrenchInflector.php b/vendor/symfony/string/Inflector/FrenchInflector.php
new file mode 100644
index 000000000..612c8f2e0
--- /dev/null
+++ b/vendor/symfony/string/Inflector/FrenchInflector.php
@@ -0,0 +1,157 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\String\Inflector;
+
+/**
+ * French inflector.
+ *
+ * This class does only inflect nouns; not adjectives nor composed words like "soixante-dix".
+ */
+final class FrenchInflector implements InflectorInterface
+{
+ /**
+ * A list of all rules for pluralise.
+ *
+ * @see https://la-conjugaison.nouvelobs.com/regles/grammaire/le-pluriel-des-noms-121.php
+ */
+ private const PLURALIZE_REGEXP = [
+ // First entry: regexp
+ // Second entry: replacement
+
+ // Words finishing with "s", "x" or "z" are invariables
+ // Les mots finissant par "s", "x" ou "z" sont invariables
+ ['/(s|x|z)$/i', '\1'],
+
+ // Words finishing with "eau" are pluralized with a "x"
+ // Les mots finissant par "eau" prennent tous un "x" au pluriel
+ ['/(eau)$/i', '\1x'],
+
+ // Words finishing with "au" are pluralized with a "x" excepted "landau"
+ // Les mots finissant par "au" prennent un "x" au pluriel sauf "landau"
+ ['/^(landau)$/i', '\1s'],
+ ['/(au)$/i', '\1x'],
+
+ // Words finishing with "eu" are pluralized with a "x" excepted "pneu", "bleu", "émeu"
+ // Les mots finissant en "eu" prennent un "x" au pluriel sauf "pneu", "bleu", "émeu"
+ ['/^(pneu|bleu|émeu)$/i', '\1s'],
+ ['/(eu)$/i', '\1x'],
+
+ // Words finishing with "al" are pluralized with a "aux" excepted
+ // Les mots finissant en "al" se terminent en "aux" sauf
+ ['/^(bal|carnaval|caracal|chacal|choral|corral|étal|festival|récital|val)$/i', '\1s'],
+ ['/al$/i', '\1aux'],
+
+ // Aspirail, bail, corail, émail, fermail, soupirail, travail, vantail et vitrail font leur pluriel en -aux
+ ['/^(aspir|b|cor|ém|ferm|soupir|trav|vant|vitr)ail$/i', '\1aux'],
+
+ // Bijou, caillou, chou, genou, hibou, joujou et pou qui prennent un x au pluriel
+ ['/^(bij|caill|ch|gen|hib|jouj|p)ou$/i', '\1oux'],
+
+ // Invariable words
+ ['/^(cinquante|soixante|mille)$/i', '\1'],
+
+ // French titles
+ ['/^(mon|ma)(sieur|dame|demoiselle|seigneur)$/', 'mes\2s'],
+ ['/^(Mon|Ma)(sieur|dame|demoiselle|seigneur)$/', 'Mes\2s'],
+ ];
+
+ /**
+ * A list of all rules for singularize.
+ */
+ private const SINGULARIZE_REGEXP = [
+ // First entry: regexp
+ // Second entry: replacement
+
+ // Aspirail, bail, corail, émail, fermail, soupirail, travail, vantail et vitrail font leur pluriel en -aux
+ ['/((aspir|b|cor|ém|ferm|soupir|trav|vant|vitr))aux$/i', '\1ail'],
+
+ // Words finishing with "eau" are pluralized with a "x"
+ // Les mots finissant par "eau" prennent tous un "x" au pluriel
+ ['/(eau)x$/i', '\1'],
+
+ // Words finishing with "al" are pluralized with a "aux" expected
+ // Les mots finissant en "al" se terminent en "aux" sauf
+ ['/(amir|anim|arsen|boc|can|capit|capor|chev|crist|génér|hopit|hôpit|idé|journ|littor|loc|m|mét|minér|princip|radic|termin)aux$/i', '\1al'],
+
+ // Words finishing with "au" are pluralized with a "x" excepted "landau"
+ // Les mots finissant par "au" prennent un "x" au pluriel sauf "landau"
+ ['/(au)x$/i', '\1'],
+
+ // Words finishing with "eu" are pluralized with a "x" excepted "pneu", "bleu", "émeu"
+ // Les mots finissant en "eu" prennent un "x" au pluriel sauf "pneu", "bleu", "émeu"
+ ['/(eu)x$/i', '\1'],
+
+ // Words finishing with "ou" are pluralized with a "s" excepted bijou, caillou, chou, genou, hibou, joujou, pou
+ // Les mots finissant par "ou" prennent un "s" sauf bijou, caillou, chou, genou, hibou, joujou, pou
+ ['/(bij|caill|ch|gen|hib|jouj|p)oux$/i', '\1ou'],
+
+ // French titles
+ ['/^mes(dame|demoiselle)s$/', 'ma\1'],
+ ['/^Mes(dame|demoiselle)s$/', 'Ma\1'],
+ ['/^mes(sieur|seigneur)s$/', 'mon\1'],
+ ['/^Mes(sieur|seigneur)s$/', 'Mon\1'],
+
+ // Default rule
+ ['/s$/i', ''],
+ ];
+
+ /**
+ * A list of words which should not be inflected.
+ * This list is only used by singularize.
+ */
+ private const UNINFLECTED = '/^(abcès|accès|abus|albatros|anchois|anglais|autobus|bois|brebis|carquois|cas|chas|colis|concours|corps|cours|cyprès|décès|devis|discours|dos|embarras|engrais|entrelacs|excès|fils|fois|gâchis|gars|glas|héros|intrus|jars|jus|kermès|lacis|legs|lilas|marais|mars|matelas|mépris|mets|mois|mors|obus|os|palais|paradis|parcours|pardessus|pays|plusieurs|poids|pois|pouls|printemps|processus|progrès|puits|pus|rabais|radis|recors|recours|refus|relais|remords|remous|rictus|rhinocéros|repas|rubis|sans|sas|secours|sens|souris|succès|talus|tapis|tas|taudis|temps|tiers|univers|velours|verglas|vernis|virus)$/i';
+
+ /**
+ * {@inheritdoc}
+ */
+ public function singularize(string $plural): array
+ {
+ if ($this->isInflectedWord($plural)) {
+ return [$plural];
+ }
+
+ foreach (self::SINGULARIZE_REGEXP as $rule) {
+ [$regexp, $replace] = $rule;
+
+ if (1 === preg_match($regexp, $plural)) {
+ return [preg_replace($regexp, $replace, $plural)];
+ }
+ }
+
+ return [$plural];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function pluralize(string $singular): array
+ {
+ if ($this->isInflectedWord($singular)) {
+ return [$singular];
+ }
+
+ foreach (self::PLURALIZE_REGEXP as $rule) {
+ [$regexp, $replace] = $rule;
+
+ if (1 === preg_match($regexp, $singular)) {
+ return [preg_replace($regexp, $replace, $singular)];
+ }
+ }
+
+ return [$singular.'s'];
+ }
+
+ private function isInflectedWord(string $word): bool
+ {
+ return 1 === preg_match(self::UNINFLECTED, $word);
+ }
+}
diff --git a/vendor/symfony/string/Inflector/InflectorInterface.php b/vendor/symfony/string/Inflector/InflectorInterface.php
new file mode 100644
index 000000000..67f283404
--- /dev/null
+++ b/vendor/symfony/string/Inflector/InflectorInterface.php
@@ -0,0 +1,33 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\String\Inflector;
+
+interface InflectorInterface
+{
+ /**
+ * Returns the singular forms of a string.
+ *
+ * If the method can't determine the form with certainty, several possible singulars are returned.
+ *
+ * @return string[]
+ */
+ public function singularize(string $plural): array;
+
+ /**
+ * Returns the plural forms of a string.
+ *
+ * If the method can't determine the form with certainty, several possible plurals are returned.
+ *
+ * @return string[]
+ */
+ public function pluralize(string $singular): array;
+}
diff --git a/vendor/symfony/string/LICENSE b/vendor/symfony/string/LICENSE
new file mode 100644
index 000000000..f37c76b59
--- /dev/null
+++ b/vendor/symfony/string/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2019-present Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/symfony/string/LazyString.php b/vendor/symfony/string/LazyString.php
new file mode 100644
index 000000000..9c7a9c58b
--- /dev/null
+++ b/vendor/symfony/string/LazyString.php
@@ -0,0 +1,164 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\String;
+
+/**
+ * A string whose value is computed lazily by a callback.
+ *
+ * @author Nicolas Grekas
+ */
+class LazyString implements \Stringable, \JsonSerializable
+{
+ private $value;
+
+ /**
+ * @param callable|array $callback A callable or a [Closure, method] lazy-callable
+ *
+ * @return static
+ */
+ public static function fromCallable($callback, ...$arguments): self
+ {
+ if (!\is_callable($callback) && !(\is_array($callback) && isset($callback[0]) && $callback[0] instanceof \Closure && 2 >= \count($callback))) {
+ throw new \TypeError(sprintf('Argument 1 passed to "%s()" must be a callable or a [Closure, method] lazy-callable, "%s" given.', __METHOD__, get_debug_type($callback)));
+ }
+
+ $lazyString = new static();
+ $lazyString->value = static function () use (&$callback, &$arguments, &$value): string {
+ if (null !== $arguments) {
+ if (!\is_callable($callback)) {
+ $callback[0] = $callback[0]();
+ $callback[1] = $callback[1] ?? '__invoke';
+ }
+ $value = $callback(...$arguments);
+ $callback = self::getPrettyName($callback);
+ $arguments = null;
+ }
+
+ return $value ?? '';
+ };
+
+ return $lazyString;
+ }
+
+ /**
+ * @param string|int|float|bool|\Stringable $value
+ *
+ * @return static
+ */
+ public static function fromStringable($value): self
+ {
+ if (!self::isStringable($value)) {
+ throw new \TypeError(sprintf('Argument 1 passed to "%s()" must be a scalar or a stringable object, "%s" given.', __METHOD__, get_debug_type($value)));
+ }
+
+ if (\is_object($value)) {
+ return static::fromCallable([$value, '__toString']);
+ }
+
+ $lazyString = new static();
+ $lazyString->value = (string) $value;
+
+ return $lazyString;
+ }
+
+ /**
+ * Tells whether the provided value can be cast to string.
+ */
+ final public static function isStringable($value): bool
+ {
+ return \is_string($value) || $value instanceof self || (\is_object($value) ? method_exists($value, '__toString') : \is_scalar($value));
+ }
+
+ /**
+ * Casts scalars and stringable objects to strings.
+ *
+ * @param object|string|int|float|bool $value
+ *
+ * @throws \TypeError When the provided value is not stringable
+ */
+ final public static function resolve($value): string
+ {
+ return $value;
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ if (\is_string($this->value)) {
+ return $this->value;
+ }
+
+ try {
+ return $this->value = ($this->value)();
+ } catch (\Throwable $e) {
+ if (\TypeError::class === \get_class($e) && __FILE__ === $e->getFile()) {
+ $type = explode(', ', $e->getMessage());
+ $type = substr(array_pop($type), 0, -\strlen(' returned'));
+ $r = new \ReflectionFunction($this->value);
+ $callback = $r->getStaticVariables()['callback'];
+
+ $e = new \TypeError(sprintf('Return value of %s() passed to %s::fromCallable() must be of the type string, %s returned.', $callback, static::class, $type));
+ }
+
+ if (\PHP_VERSION_ID < 70400) {
+ // leverage the ErrorHandler component with graceful fallback when it's not available
+ return trigger_error($e, \E_USER_ERROR);
+ }
+
+ throw $e;
+ }
+ }
+
+ public function __sleep(): array
+ {
+ $this->__toString();
+
+ return ['value'];
+ }
+
+ public function jsonSerialize(): string
+ {
+ return $this->__toString();
+ }
+
+ private function __construct()
+ {
+ }
+
+ private static function getPrettyName(callable $callback): string
+ {
+ if (\is_string($callback)) {
+ return $callback;
+ }
+
+ if (\is_array($callback)) {
+ $class = \is_object($callback[0]) ? get_debug_type($callback[0]) : $callback[0];
+ $method = $callback[1];
+ } elseif ($callback instanceof \Closure) {
+ $r = new \ReflectionFunction($callback);
+
+ if (false !== strpos($r->name, '{closure}') || !$class = \PHP_VERSION_ID >= 80111 ? $r->getClosureCalledClass() : $r->getClosureScopeClass()) {
+ return $r->name;
+ }
+
+ $class = $class->name;
+ $method = $r->name;
+ } else {
+ $class = get_debug_type($callback);
+ $method = '__invoke';
+ }
+
+ return $class.'::'.$method;
+ }
+}
diff --git a/vendor/symfony/string/README.md b/vendor/symfony/string/README.md
new file mode 100644
index 000000000..9c7e1e190
--- /dev/null
+++ b/vendor/symfony/string/README.md
@@ -0,0 +1,14 @@
+String Component
+================
+
+The String component provides an object-oriented API to strings and deals
+with bytes, UTF-8 code points and grapheme clusters in a unified way.
+
+Resources
+---------
+
+ * [Documentation](https://symfony.com/doc/current/components/string.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)
diff --git a/vendor/symfony/string/Resources/data/wcswidth_table_wide.php b/vendor/symfony/string/Resources/data/wcswidth_table_wide.php
new file mode 100644
index 000000000..5a647e67b
--- /dev/null
+++ b/vendor/symfony/string/Resources/data/wcswidth_table_wide.php
@@ -0,0 +1,1143 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\String;
+
+if (!\function_exists(u::class)) {
+ function u(?string $string = ''): UnicodeString
+ {
+ return new UnicodeString($string ?? '');
+ }
+}
+
+if (!\function_exists(b::class)) {
+ function b(?string $string = ''): ByteString
+ {
+ return new ByteString($string ?? '');
+ }
+}
+
+if (!\function_exists(s::class)) {
+ /**
+ * @return UnicodeString|ByteString
+ */
+ function s(?string $string = ''): AbstractString
+ {
+ $string = $string ?? '';
+
+ return preg_match('//u', $string) ? new UnicodeString($string) : new ByteString($string);
+ }
+}
diff --git a/vendor/symfony/string/Slugger/AsciiSlugger.php b/vendor/symfony/string/Slugger/AsciiSlugger.php
new file mode 100644
index 000000000..5aecfeb5f
--- /dev/null
+++ b/vendor/symfony/string/Slugger/AsciiSlugger.php
@@ -0,0 +1,183 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\String\Slugger;
+
+use Symfony\Component\String\AbstractUnicodeString;
+use Symfony\Component\String\UnicodeString;
+use Symfony\Contracts\Translation\LocaleAwareInterface;
+
+if (!interface_exists(LocaleAwareInterface::class)) {
+ throw new \LogicException('You cannot use the "Symfony\Component\String\Slugger\AsciiSlugger" as the "symfony/translation-contracts" package is not installed. Try running "composer require symfony/translation-contracts".');
+}
+
+/**
+ * @author Titouan Galopin
+ */
+class AsciiSlugger implements SluggerInterface, LocaleAwareInterface
+{
+ private const LOCALE_TO_TRANSLITERATOR_ID = [
+ 'am' => 'Amharic-Latin',
+ 'ar' => 'Arabic-Latin',
+ 'az' => 'Azerbaijani-Latin',
+ 'be' => 'Belarusian-Latin',
+ 'bg' => 'Bulgarian-Latin',
+ 'bn' => 'Bengali-Latin',
+ 'de' => 'de-ASCII',
+ 'el' => 'Greek-Latin',
+ 'fa' => 'Persian-Latin',
+ 'he' => 'Hebrew-Latin',
+ 'hy' => 'Armenian-Latin',
+ 'ka' => 'Georgian-Latin',
+ 'kk' => 'Kazakh-Latin',
+ 'ky' => 'Kirghiz-Latin',
+ 'ko' => 'Korean-Latin',
+ 'mk' => 'Macedonian-Latin',
+ 'mn' => 'Mongolian-Latin',
+ 'or' => 'Oriya-Latin',
+ 'ps' => 'Pashto-Latin',
+ 'ru' => 'Russian-Latin',
+ 'sr' => 'Serbian-Latin',
+ 'sr_Cyrl' => 'Serbian-Latin',
+ 'th' => 'Thai-Latin',
+ 'tk' => 'Turkmen-Latin',
+ 'uk' => 'Ukrainian-Latin',
+ 'uz' => 'Uzbek-Latin',
+ 'zh' => 'Han-Latin',
+ ];
+
+ private $defaultLocale;
+ private $symbolsMap = [
+ 'en' => ['@' => 'at', '&' => 'and'],
+ ];
+
+ /**
+ * Cache of transliterators per locale.
+ *
+ * @var \Transliterator[]
+ */
+ private $transliterators = [];
+
+ /**
+ * @param array|\Closure|null $symbolsMap
+ */
+ public function __construct(string $defaultLocale = null, $symbolsMap = null)
+ {
+ if (null !== $symbolsMap && !\is_array($symbolsMap) && !$symbolsMap instanceof \Closure) {
+ throw new \TypeError(sprintf('Argument 2 passed to "%s()" must be array, Closure or null, "%s" given.', __METHOD__, \gettype($symbolsMap)));
+ }
+
+ $this->defaultLocale = $defaultLocale;
+ $this->symbolsMap = $symbolsMap ?? $this->symbolsMap;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setLocale($locale)
+ {
+ $this->defaultLocale = $locale;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getLocale()
+ {
+ return $this->defaultLocale;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function slug(string $string, string $separator = '-', string $locale = null): AbstractUnicodeString
+ {
+ $locale = $locale ?? $this->defaultLocale;
+
+ $transliterator = [];
+ if ($locale && ('de' === $locale || 0 === strpos($locale, 'de_'))) {
+ // Use the shortcut for German in UnicodeString::ascii() if possible (faster and no requirement on intl)
+ $transliterator = ['de-ASCII'];
+ } elseif (\function_exists('transliterator_transliterate') && $locale) {
+ $transliterator = (array) $this->createTransliterator($locale);
+ }
+
+ if ($this->symbolsMap instanceof \Closure) {
+ // If the symbols map is passed as a closure, there is no need to fallback to the parent locale
+ // as the closure can just provide substitutions for all locales of interest.
+ $symbolsMap = $this->symbolsMap;
+ array_unshift($transliterator, static function ($s) use ($symbolsMap, $locale) {
+ return $symbolsMap($s, $locale);
+ });
+ }
+
+ $unicodeString = (new UnicodeString($string))->ascii($transliterator);
+
+ if (\is_array($this->symbolsMap)) {
+ $map = null;
+ if (isset($this->symbolsMap[$locale])) {
+ $map = $this->symbolsMap[$locale];
+ } else {
+ $parent = self::getParentLocale($locale);
+ if ($parent && isset($this->symbolsMap[$parent])) {
+ $map = $this->symbolsMap[$parent];
+ }
+ }
+ if ($map) {
+ foreach ($map as $char => $replace) {
+ $unicodeString = $unicodeString->replace($char, ' '.$replace.' ');
+ }
+ }
+ }
+
+ return $unicodeString
+ ->replaceMatches('/[^A-Za-z0-9]++/', $separator)
+ ->trim($separator)
+ ;
+ }
+
+ private function createTransliterator(string $locale): ?\Transliterator
+ {
+ if (\array_key_exists($locale, $this->transliterators)) {
+ return $this->transliterators[$locale];
+ }
+
+ // Exact locale supported, cache and return
+ if ($id = self::LOCALE_TO_TRANSLITERATOR_ID[$locale] ?? null) {
+ return $this->transliterators[$locale] = \Transliterator::create($id.'/BGN') ?? \Transliterator::create($id);
+ }
+
+ // Locale not supported and no parent, fallback to any-latin
+ if (!$parent = self::getParentLocale($locale)) {
+ return $this->transliterators[$locale] = null;
+ }
+
+ // Try to use the parent locale (ie. try "de" for "de_AT") and cache both locales
+ if ($id = self::LOCALE_TO_TRANSLITERATOR_ID[$parent] ?? null) {
+ $transliterator = \Transliterator::create($id.'/BGN') ?? \Transliterator::create($id);
+ }
+
+ return $this->transliterators[$locale] = $this->transliterators[$parent] = $transliterator ?? null;
+ }
+
+ private static function getParentLocale(?string $locale): ?string
+ {
+ if (!$locale) {
+ return null;
+ }
+ if (false === $str = strrchr($locale, '_')) {
+ // no parent locale
+ return null;
+ }
+
+ return substr($locale, 0, -\strlen($str));
+ }
+}
diff --git a/vendor/symfony/string/Slugger/SluggerInterface.php b/vendor/symfony/string/Slugger/SluggerInterface.php
new file mode 100644
index 000000000..c679ed933
--- /dev/null
+++ b/vendor/symfony/string/Slugger/SluggerInterface.php
@@ -0,0 +1,27 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\String\Slugger;
+
+use Symfony\Component\String\AbstractUnicodeString;
+
+/**
+ * Creates a URL-friendly slug from a given string.
+ *
+ * @author Titouan Galopin
+ */
+interface SluggerInterface
+{
+ /**
+ * Creates a slug for the given string and locale, using appropriate transliteration when needed.
+ */
+ public function slug(string $string, string $separator = '-', string $locale = null): AbstractUnicodeString;
+}
diff --git a/vendor/symfony/string/UnicodeString.php b/vendor/symfony/string/UnicodeString.php
new file mode 100644
index 000000000..9b906c6fc
--- /dev/null
+++ b/vendor/symfony/string/UnicodeString.php
@@ -0,0 +1,377 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\String;
+
+use Symfony\Component\String\Exception\ExceptionInterface;
+use Symfony\Component\String\Exception\InvalidArgumentException;
+
+/**
+ * Represents a string of Unicode grapheme clusters encoded as UTF-8.
+ *
+ * A letter followed by combining characters (accents typically) form what Unicode defines
+ * as a grapheme cluster: a character as humans mean it in written texts. This class knows
+ * about the concept and won't split a letter apart from its combining accents. It also
+ * ensures all string comparisons happen on their canonically-composed representation,
+ * ignoring e.g. the order in which accents are listed when a letter has many of them.
+ *
+ * @see https://unicode.org/reports/tr15/
+ *
+ * @author Nicolas Grekas
+ * @author Hugo Hamon
+ *
+ * @throws ExceptionInterface
+ */
+class UnicodeString extends AbstractUnicodeString
+{
+ public function __construct(string $string = '')
+ {
+ $this->string = normalizer_is_normalized($string) ? $string : normalizer_normalize($string);
+
+ if (false === $this->string) {
+ throw new InvalidArgumentException('Invalid UTF-8 string.');
+ }
+ }
+
+ public function append(string ...$suffix): AbstractString
+ {
+ $str = clone $this;
+ $str->string = $this->string.(1 >= \count($suffix) ? ($suffix[0] ?? '') : implode('', $suffix));
+ normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string);
+
+ if (false === $str->string) {
+ throw new InvalidArgumentException('Invalid UTF-8 string.');
+ }
+
+ return $str;
+ }
+
+ public function chunk(int $length = 1): array
+ {
+ if (1 > $length) {
+ throw new InvalidArgumentException('The chunk length must be greater than zero.');
+ }
+
+ if ('' === $this->string) {
+ return [];
+ }
+
+ $rx = '/(';
+ while (65535 < $length) {
+ $rx .= '\X{65535}';
+ $length -= 65535;
+ }
+ $rx .= '\X{'.$length.'})/u';
+
+ $str = clone $this;
+ $chunks = [];
+
+ foreach (preg_split($rx, $this->string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY) as $chunk) {
+ $str->string = $chunk;
+ $chunks[] = clone $str;
+ }
+
+ return $chunks;
+ }
+
+ public function endsWith($suffix): bool
+ {
+ if ($suffix instanceof AbstractString) {
+ $suffix = $suffix->string;
+ } elseif (\is_array($suffix) || $suffix instanceof \Traversable) {
+ return parent::endsWith($suffix);
+ } else {
+ $suffix = (string) $suffix;
+ }
+
+ $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC;
+ normalizer_is_normalized($suffix, $form) ?: $suffix = normalizer_normalize($suffix, $form);
+
+ if ('' === $suffix || false === $suffix) {
+ return false;
+ }
+
+ if ($this->ignoreCase) {
+ return 0 === mb_stripos(grapheme_extract($this->string, \strlen($suffix), \GRAPHEME_EXTR_MAXBYTES, \strlen($this->string) - \strlen($suffix)), $suffix, 0, 'UTF-8');
+ }
+
+ return $suffix === grapheme_extract($this->string, \strlen($suffix), \GRAPHEME_EXTR_MAXBYTES, \strlen($this->string) - \strlen($suffix));
+ }
+
+ public function equalsTo($string): bool
+ {
+ if ($string instanceof AbstractString) {
+ $string = $string->string;
+ } elseif (\is_array($string) || $string instanceof \Traversable) {
+ return parent::equalsTo($string);
+ } else {
+ $string = (string) $string;
+ }
+
+ $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC;
+ normalizer_is_normalized($string, $form) ?: $string = normalizer_normalize($string, $form);
+
+ if ('' !== $string && false !== $string && $this->ignoreCase) {
+ return \strlen($string) === \strlen($this->string) && 0 === mb_stripos($this->string, $string, 0, 'UTF-8');
+ }
+
+ return $string === $this->string;
+ }
+
+ public function indexOf($needle, int $offset = 0): ?int
+ {
+ if ($needle instanceof AbstractString) {
+ $needle = $needle->string;
+ } elseif (\is_array($needle) || $needle instanceof \Traversable) {
+ return parent::indexOf($needle, $offset);
+ } else {
+ $needle = (string) $needle;
+ }
+
+ $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC;
+ normalizer_is_normalized($needle, $form) ?: $needle = normalizer_normalize($needle, $form);
+
+ if ('' === $needle || false === $needle) {
+ return null;
+ }
+
+ try {
+ $i = $this->ignoreCase ? grapheme_stripos($this->string, $needle, $offset) : grapheme_strpos($this->string, $needle, $offset);
+ } catch (\ValueError $e) {
+ return null;
+ }
+
+ return false === $i ? null : $i;
+ }
+
+ public function indexOfLast($needle, int $offset = 0): ?int
+ {
+ if ($needle instanceof AbstractString) {
+ $needle = $needle->string;
+ } elseif (\is_array($needle) || $needle instanceof \Traversable) {
+ return parent::indexOfLast($needle, $offset);
+ } else {
+ $needle = (string) $needle;
+ }
+
+ $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC;
+ normalizer_is_normalized($needle, $form) ?: $needle = normalizer_normalize($needle, $form);
+
+ if ('' === $needle || false === $needle) {
+ return null;
+ }
+
+ $string = $this->string;
+
+ if (0 > $offset) {
+ // workaround https://bugs.php.net/74264
+ if (0 > $offset += grapheme_strlen($needle)) {
+ $string = grapheme_substr($string, 0, $offset);
+ }
+ $offset = 0;
+ }
+
+ $i = $this->ignoreCase ? grapheme_strripos($string, $needle, $offset) : grapheme_strrpos($string, $needle, $offset);
+
+ return false === $i ? null : $i;
+ }
+
+ public function join(array $strings, string $lastGlue = null): AbstractString
+ {
+ $str = parent::join($strings, $lastGlue);
+ normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string);
+
+ return $str;
+ }
+
+ public function length(): int
+ {
+ return grapheme_strlen($this->string);
+ }
+
+ /**
+ * @return static
+ */
+ public function normalize(int $form = self::NFC): parent
+ {
+ $str = clone $this;
+
+ if (\in_array($form, [self::NFC, self::NFKC], true)) {
+ normalizer_is_normalized($str->string, $form) ?: $str->string = normalizer_normalize($str->string, $form);
+ } elseif (!\in_array($form, [self::NFD, self::NFKD], true)) {
+ throw new InvalidArgumentException('Unsupported normalization form.');
+ } elseif (!normalizer_is_normalized($str->string, $form)) {
+ $str->string = normalizer_normalize($str->string, $form);
+ $str->ignoreCase = null;
+ }
+
+ return $str;
+ }
+
+ public function prepend(string ...$prefix): AbstractString
+ {
+ $str = clone $this;
+ $str->string = (1 >= \count($prefix) ? ($prefix[0] ?? '') : implode('', $prefix)).$this->string;
+ normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string);
+
+ if (false === $str->string) {
+ throw new InvalidArgumentException('Invalid UTF-8 string.');
+ }
+
+ return $str;
+ }
+
+ public function replace(string $from, string $to): AbstractString
+ {
+ $str = clone $this;
+ normalizer_is_normalized($from) ?: $from = normalizer_normalize($from);
+
+ if ('' !== $from && false !== $from) {
+ $tail = $str->string;
+ $result = '';
+ $indexOf = $this->ignoreCase ? 'grapheme_stripos' : 'grapheme_strpos';
+
+ while ('' !== $tail && false !== $i = $indexOf($tail, $from)) {
+ $slice = grapheme_substr($tail, 0, $i);
+ $result .= $slice.$to;
+ $tail = substr($tail, \strlen($slice) + \strlen($from));
+ }
+
+ $str->string = $result.$tail;
+ normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string);
+
+ if (false === $str->string) {
+ throw new InvalidArgumentException('Invalid UTF-8 string.');
+ }
+ }
+
+ return $str;
+ }
+
+ public function replaceMatches(string $fromRegexp, $to): AbstractString
+ {
+ $str = parent::replaceMatches($fromRegexp, $to);
+ normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string);
+
+ return $str;
+ }
+
+ public function slice(int $start = 0, int $length = null): AbstractString
+ {
+ $str = clone $this;
+
+ if (\PHP_VERSION_ID < 80000 && 0 > $start && grapheme_strlen($this->string) < -$start) {
+ $start = 0;
+ }
+ $str->string = (string) grapheme_substr($this->string, $start, $length ?? 2147483647);
+
+ return $str;
+ }
+
+ public function splice(string $replacement, int $start = 0, int $length = null): AbstractString
+ {
+ $str = clone $this;
+
+ if (\PHP_VERSION_ID < 80000 && 0 > $start && grapheme_strlen($this->string) < -$start) {
+ $start = 0;
+ }
+ $start = $start ? \strlen(grapheme_substr($this->string, 0, $start)) : 0;
+ $length = $length ? \strlen(grapheme_substr($this->string, $start, $length ?? 2147483647)) : $length;
+ $str->string = substr_replace($this->string, $replacement, $start, $length ?? 2147483647);
+ normalizer_is_normalized($str->string) ?: $str->string = normalizer_normalize($str->string);
+
+ if (false === $str->string) {
+ throw new InvalidArgumentException('Invalid UTF-8 string.');
+ }
+
+ return $str;
+ }
+
+ public function split(string $delimiter, int $limit = null, int $flags = null): array
+ {
+ if (1 > $limit = $limit ?? 2147483647) {
+ throw new InvalidArgumentException('Split limit must be a positive integer.');
+ }
+
+ if ('' === $delimiter) {
+ throw new InvalidArgumentException('Split delimiter is empty.');
+ }
+
+ if (null !== $flags) {
+ return parent::split($delimiter.'u', $limit, $flags);
+ }
+
+ normalizer_is_normalized($delimiter) ?: $delimiter = normalizer_normalize($delimiter);
+
+ if (false === $delimiter) {
+ throw new InvalidArgumentException('Split delimiter is not a valid UTF-8 string.');
+ }
+
+ $str = clone $this;
+ $tail = $this->string;
+ $chunks = [];
+ $indexOf = $this->ignoreCase ? 'grapheme_stripos' : 'grapheme_strpos';
+
+ while (1 < $limit && false !== $i = $indexOf($tail, $delimiter)) {
+ $str->string = grapheme_substr($tail, 0, $i);
+ $chunks[] = clone $str;
+ $tail = substr($tail, \strlen($str->string) + \strlen($delimiter));
+ --$limit;
+ }
+
+ $str->string = $tail;
+ $chunks[] = clone $str;
+
+ return $chunks;
+ }
+
+ public function startsWith($prefix): bool
+ {
+ if ($prefix instanceof AbstractString) {
+ $prefix = $prefix->string;
+ } elseif (\is_array($prefix) || $prefix instanceof \Traversable) {
+ return parent::startsWith($prefix);
+ } else {
+ $prefix = (string) $prefix;
+ }
+
+ $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC;
+ normalizer_is_normalized($prefix, $form) ?: $prefix = normalizer_normalize($prefix, $form);
+
+ if ('' === $prefix || false === $prefix) {
+ return false;
+ }
+
+ if ($this->ignoreCase) {
+ return 0 === mb_stripos(grapheme_extract($this->string, \strlen($prefix), \GRAPHEME_EXTR_MAXBYTES), $prefix, 0, 'UTF-8');
+ }
+
+ return $prefix === grapheme_extract($this->string, \strlen($prefix), \GRAPHEME_EXTR_MAXBYTES);
+ }
+
+ public function __wakeup()
+ {
+ if (!\is_string($this->string)) {
+ throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
+ }
+
+ normalizer_is_normalized($this->string) ?: $this->string = normalizer_normalize($this->string);
+ }
+
+ public function __clone()
+ {
+ if (null === $this->ignoreCase) {
+ normalizer_is_normalized($this->string) ?: $this->string = normalizer_normalize($this->string);
+ }
+
+ $this->ignoreCase = false;
+ }
+}
diff --git a/vendor/symfony/string/composer.json b/vendor/symfony/string/composer.json
new file mode 100644
index 000000000..2b88fd529
--- /dev/null
+++ b/vendor/symfony/string/composer.json
@@ -0,0 +1,43 @@
+{
+ "name": "symfony/string",
+ "type": "library",
+ "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way",
+ "keywords": ["string", "utf8", "utf-8", "grapheme", "i18n", "unicode"],
+ "homepage": "https://symfony.com",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=7.2.5",
+ "symfony/polyfill-ctype": "~1.8",
+ "symfony/polyfill-intl-grapheme": "~1.0",
+ "symfony/polyfill-intl-normalizer": "~1.0",
+ "symfony/polyfill-mbstring": "~1.0",
+ "symfony/polyfill-php80": "~1.15"
+ },
+ "require-dev": {
+ "symfony/error-handler": "^4.4|^5.0|^6.0",
+ "symfony/http-client": "^4.4|^5.0|^6.0",
+ "symfony/translation-contracts": "^1.1|^2",
+ "symfony/var-exporter": "^4.4|^5.0|^6.0"
+ },
+ "conflict": {
+ "symfony/translation-contracts": ">=3.0"
+ },
+ "autoload": {
+ "psr-4": { "Symfony\\Component\\String\\": "" },
+ "files": [ "Resources/functions.php" ],
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "minimum-stability": "dev"
+}