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 cece7829..c66ef463 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 @@ protected function configure()
->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 @@ protected function execute(InputInterface $input, OutputInterface $output)
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 00000000..e576ad03
--- /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 44324a5e..f04a4ef6 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 @@ protected function configure()
{
$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 @@ protected function execute(InputInterface $input, OutputInterface $output)
'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 60cfe360..b1856dca 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 @@
*/
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 00000000..d439728b
--- /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 ca1029cb..0adaf886 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 50e5950a..ddccb3d4 100644
--- a/vendor/symfony/console/CommandLoader/ContainerCommandLoader.php
+++ b/vendor/symfony/console/CommandLoader/ContainerCommandLoader.php
@@ -36,7 +36,7 @@ public function __construct(ContainerInterface $container, array $commandMap)
/**
* {@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 @@ public function get($name)
/**
* {@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 d9c20557..7e2db346 100644
--- a/vendor/symfony/console/CommandLoader/FactoryCommandLoader.php
+++ b/vendor/symfony/console/CommandLoader/FactoryCommandLoader.php
@@ -33,7 +33,7 @@ public function __construct(array $factories)
/**
* {@inheritdoc}
*/
- public function has($name)
+ public function has(string $name)
{
return isset($this->factories[$name]);
}
@@ -41,7 +41,7 @@ public function has($name)
/**
* {@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 00000000..368b9450
--- /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 00000000..d8905e5e
--- /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 00000000..c6f76eb8
--- /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 00000000..659e5965
--- /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 00000000..6c7bc4dc
--- /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 99b423c8..6ae8f32b 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 00000000..0c4dafb6
--- /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 d9449dc5..1fbb212e 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 @@ public function process(ContainerBuilder $container)
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 @@ public function process(ContainerBuilder $container)
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 = null !== $class::getDefaultName() ? str_replace('%', '%%', $class::getDefaultName()) : null;
+ $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 @@ public function process(ContainerBuilder $container)
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 @@ public function process(ContainerBuilder $container)
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 91b18460..2a3acc99 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;
diff --git a/vendor/symfony/console/Descriptor/Descriptor.php b/vendor/symfony/console/Descriptor/Descriptor.php
index 9c3878d1..a3648301 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 @@ public function describe(OutputInterface $output, $object, array $options = [])
$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 e3184a6a..ebea3036 100644
--- a/vendor/symfony/console/Descriptor/DescriptorInterface.php
+++ b/vendor/symfony/console/Descriptor/DescriptorInterface.php
@@ -20,10 +20,5 @@
*/
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 4c09e126..1d286594 100644
--- a/vendor/symfony/console/Descriptor/JsonDescriptor.php
+++ b/vendor/symfony/console/Descriptor/JsonDescriptor.php
@@ -40,6 +40,9 @@ protected function describeInputArgument(InputArgument $argument, array $options
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 @@ protected function describeInputDefinition(InputDefinition $definition, array $o
*/
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 @@ protected function describeApplication(Application $application, array $options
$commands = [];
foreach ($description->getCommands() as $command) {
- $commands[] = $this->getCommandData($command);
+ $commands[] = $this->getCommandData($command, $options['short'] ?? false);
}
$data = [];
@@ -111,9 +114,17 @@ private function getInputArgumentData(InputArgument $argument): array
];
}
- 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 @@ private function getInputDefinitionData(InputDefinition $definition): array
$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 9a9d2807..21ceca6c 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 @@ public function describe(OutputInterface $output, $object, array $options = [])
/**
* {@inheritdoc}
*/
- protected function write($content, $decorated = true)
+ protected function write(string $content, bool $decorated = true)
{
parent::write($content, $decorated);
}
@@ -69,6 +69,9 @@ protected function describeInputArgument(InputArgument $argument, array $options
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 @@ protected function describeInputOption(InputOption $option, array $options = [])
.'* 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 @@ protected function describeInputDefinition(InputDefinition $definition, array $o
$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 @@ protected function describeInputDefinition(InputDefinition $definition, array $o
$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 @@ protected function describeInputDefinition(InputDefinition $definition, array $o
*/
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 @@ protected function describeCommand(Command $command, array $options = [])
$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 @@ protected function describeApplication(Application $application, array $options
$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 @@ protected function describeApplication(Application $application, array $options
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 7d4d5f0b..fbb140ae 100644
--- a/vendor/symfony/console/Descriptor/TextDescriptor.php
+++ b/vendor/symfony/console/Descriptor/TextDescriptor.php
@@ -39,7 +39,7 @@ protected function describeInputArgument(InputArgument $argument, array $options
$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 @@ protected function describeInputOption(InputOption $option, array $options = [])
$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 @@ protected function describeInputDefinition(InputDefinition $definition, array $o
{
$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 @@ protected function describeInputDefinition(InputDefinition $definition, array $o
*/
protected function describeCommand(Command $command, array $options = [])
{
- $command->getSynopsis(true);
- $command->getSynopsis(false);
$command->mergeApplicationDefinition(false);
if ($description = $command->getDescription()) {
@@ -154,7 +152,7 @@ protected function describeCommand(Command $command, array $options = [])
}
$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 @@ protected function describeApplication(Application $application, array $options
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 @@ private function getColumnWidth(array $commands): int
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 @@ private function calculateTotalWidthForOptions(array $options): int
$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 e0ed53a3..4f7cd8b3 100644
--- a/vendor/symfony/console/Descriptor/XmlDescriptor.php
+++ b/vendor/symfony/console/Descriptor/XmlDescriptor.php
@@ -44,37 +44,42 @@ public function getInputDefinitionDocument(InputDefinition $definition): \DOMDoc
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 @@ public function getApplicationDocument(Application $application, string $namespa
}
foreach ($description->getCommands() as $command) {
- $this->appendDocument($commandsXML, $this->getCommandDocument($command));
+ $this->appendDocument($commandsXML, $this->getCommandDocument($command, $short));
}
if (!$namespace) {
@@ -144,7 +149,7 @@ protected function describeInputDefinition(InputDefinition $definition, array $o
*/
protected function describeCommand(Command $command, array $options = [])
{
- $this->writeDocument($this->getCommandDocument($command));
+ $this->writeDocument($this->getCommandDocument($command, $options['short'] ?? false));
}
/**
@@ -152,7 +157,7 @@ protected function describeCommand(Command $command, array $options = [])
*/
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 @@ private function getInputOptionDocument(InputOption $option): \DOMDocument
}
}
+ 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 9691db63..08bd18fd 100644
--- a/vendor/symfony/console/Event/ConsoleCommandEvent.php
+++ b/vendor/symfony/console/Event/ConsoleCommandEvent.php
@@ -15,10 +15,8 @@
* 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 400eb573..be7937d5 100644
--- a/vendor/symfony/console/Event/ConsoleEvent.php
+++ b/vendor/symfony/console/Event/ConsoleEvent.php
@@ -14,7 +14,7 @@
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 @@ public function __construct(?Command $command, InputInterface $input, OutputInte
/**
* Gets the command that is executed.
*
- * @return Command|null A Command instance
+ * @return Command|null
*/
public function getCommand()
{
@@ -48,7 +48,7 @@ public function getCommand()
/**
* Gets the input instance.
*
- * @return InputInterface An InputInterface instance
+ * @return InputInterface
*/
public function getInput()
{
@@ -58,7 +58,7 @@ public function getInput()
/**
* 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 00000000..ef13ed2f
--- /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 43d0f8ab..190038d1 100644
--- a/vendor/symfony/console/Event/ConsoleTerminateEvent.php
+++ b/vendor/symfony/console/Event/ConsoleTerminateEvent.php
@@ -19,10 +19,8 @@
* 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 @@ public function __construct(Command $command, InputInterface $input, OutputInter
$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 590a71c7..910ae192 100644
--- a/vendor/symfony/console/Exception/CommandNotFoundException.php
+++ b/vendor/symfony/console/Exception/CommandNotFoundException.php
@@ -34,7 +34,7 @@ public function __construct(string $message, array $alternatives = [], int $code
}
/**
- * @return string[] A list of similar defined names
+ * @return string[]
*/
public function getAlternatives()
{
diff --git a/vendor/symfony/console/Formatter/NullOutputFormatter.php b/vendor/symfony/console/Formatter/NullOutputFormatter.php
new file mode 100644
index 00000000..d770e146
--- /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 00000000..9232510f
--- /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 e8c10e70..4ec60024 100644
--- a/vendor/symfony/console/Formatter/OutputFormatter.php
+++ b/vendor/symfony/console/Formatter/OutputFormatter.php
@@ -13,6 +13,8 @@
use Symfony\Component\Console\Exception\InvalidArgumentException;
+use function Symfony\Component\String\b;
+
/**
* Formatter class for console output.
*
@@ -36,11 +38,9 @@ public function __clone()
/**
* 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 +88,9 @@ public function __construct(bool $decorated = false, array $styles = [])
/**
* {@inheritdoc}
*/
- public function setDecorated($decorated)
+ public function setDecorated(bool $decorated)
{
- $this->decorated = (bool) $decorated;
+ $this->decorated = $decorated;
}
/**
@@ -104,7 +104,7 @@ public function isDecorated()
/**
* {@inheritdoc}
*/
- public function setStyle($name, OutputFormatterStyleInterface $style)
+ public function setStyle(string $name, OutputFormatterStyleInterface $style)
{
$this->styles[strtolower($name)] = $style;
}
@@ -112,7 +112,7 @@ public function setStyle($name, OutputFormatterStyleInterface $style)
/**
* {@inheritdoc}
*/
- public function hasStyle($name)
+ public function hasStyle(string $name)
{
return isset($this->styles[strtolower($name)]);
}
@@ -120,7 +120,7 @@ public function hasStyle($name)
/**
* {@inheritdoc}
*/
- public function getStyle($name)
+ public function getStyle(string $name)
{
if (!$this->hasStyle($name)) {
throw new InvalidArgumentException(sprintf('Undefined style: "%s".', $name));
@@ -132,16 +132,20 @@ public function getStyle($name)
/**
* {@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](?:[^\\\\<>]*+ | \\\\.)*';
@@ -256,7 +260,7 @@ private function applyCurrentStyle(string $text, string $current, int $width, in
}
preg_match('~(\\n)$~', $text, $matches);
- $text = $prefix.preg_replace('~([^\\n]{'.$width.'})\\ *~', "\$1\n", $text);
+ $text = $prefix.$this->addLineBreaks($text, $width);
$text = rtrim($text, "\n").($matches[1] ?? '');
if (!$currentLineLength && '' !== $current && "\n" !== substr($current, -1)) {
@@ -280,4 +284,11 @@ private function applyCurrentStyle(string $text, string $current, int $width, in
return implode("\n", $lines);
}
+
+ private function addLineBreaks(string $text, int $width): string
+ {
+ $encoding = mb_detect_encoding($text, null, true) ?: 'UTF-8';
+
+ return b($text)->toCodePointString($encoding)->wordwrap($width, "\n", true)->toByteString($encoding);
+ }
}
diff --git a/vendor/symfony/console/Formatter/OutputFormatterInterface.php b/vendor/symfony/console/Formatter/OutputFormatterInterface.php
index 22f40a34..0b5f839a 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 7cb6116b..8370ba05 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 @@
*/
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 @@ public function setHref(string $url): void
/**
* {@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 @@ public function unsetOption($option)
*/
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 af171c27..b30560d2 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 @@ public function setOptions(array $options);
/**
* 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 6694053f..42319ee5 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 1653edeb..e258ba05 100644
--- a/vendor/symfony/console/Helper/DebugFormatterHelper.php
+++ b/vendor/symfony/console/Helper/DebugFormatterHelper.php
@@ -20,22 +20,18 @@
*/
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 @@ public function start($id, $message, $prefix = 'RUN')
/**
* 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 @@ public function progress($id, $buffer, $error = false, $prefix = 'OUT', $errorPr
/**
* 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 @@ public function stop($id, $message, $successful, $prefix = 'RES')
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 3055baef..af85e9c0 100644
--- a/vendor/symfony/console/Helper/DescriptorHelper.php
+++ b/vendor/symfony/console/Helper/DescriptorHelper.php
@@ -48,11 +48,9 @@ public function __construct()
* * 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 @@ public function describe(OutputInterface $output, $object, array $options = [])
/**
* 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 @@ public function getName()
{
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 d6eccee8..92d8dc72 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 @@ public function formatSection($section, $message, $style = 'info')
* 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 @@ public function formatBlock($messages, $style, $large = false)
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 @@ public function formatBlock($messages, $style, $large = false)
/**
* 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 18d85b94..c7d3e25d 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 @@ public function getHelperSet()
/**
* 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 @@ public static function strlen($string)
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 @@ public static function formatTime($secs)
}
}
- 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,21 +153,26 @@ public static function formatMemory($memory)
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);
+ $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 1ce82358..fc952b48 100644
--- a/vendor/symfony/console/Helper/HelperInterface.php
+++ b/vendor/symfony/console/Helper/HelperInterface.php
@@ -26,14 +26,14 @@ public function setHelperSet(HelperSet $helperSet = null);
/**
* 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 9aa1e67b..719762d2 100644
--- a/vendor/symfony/console/Helper/HelperSet.php
+++ b/vendor/symfony/console/Helper/HelperSet.php
@@ -18,12 +18,12 @@
* 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 @@ public function __construct(array $helpers = [])
}
}
- /**
- * 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 @@ public function set(HelperInterface $helper, $alias = null)
/**
* 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 @@ public function has($name)
/**
* 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 @@ public function get($name)
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 862d09f2..4ea3d724 100644
--- a/vendor/symfony/console/Helper/ProcessHelper.php
+++ b/vendor/symfony/console/Helper/ProcessHelper.php
@@ -21,22 +21,18 @@
*
* @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 @@ public function run(OutputInterface $output, $cmd, $error = null, callable $call
}
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 @@ public function run(OutputInterface $output, $cmd, $error = null, callable $call
* 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 @@ public function mustRun(OutputInterface $output, $cmd, $error = null, callable $
/**
* 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 @@ private function escapeString(string $str): string
/**
* {@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 1de9b7b3..eb6aacb1 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 @@
*/
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 @@ public function __construct(OutputInterface $output, int $max = 0, float $minSec
}
$this->startTime = time();
+ $this->cursor = new Cursor($output);
}
/**
@@ -101,8 +113,6 @@ public static function setPlaceholderFormatterDefinition(string $name, callable
* 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 @@ public static function setFormatDefinition(string $name, string $format): void
* 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 @@ public function getProgressPercent(): float
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 @@ public function setBarCharacter(string $char)
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 @@ public function setMaxSteps(int $max)
{
$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 @@ private function setRealFormat(string $format)
} else {
$this->format = $format;
}
-
- $this->formatLineCount = substr_count($this->format, "\n");
}
/**
@@ -441,23 +461,25 @@ private function overwrite(string $message): void
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 @@ private function determineBestFormat(): string
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 @@ private static function initPlaceholderFormatters(): array
$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 @@ private static function initPlaceholderFormatters(): array
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 @@ private static function initPlaceholderFormatters(): array
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 @@ private function buildLine(): string
// 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 dc37148e..3482343f 100644
--- a/vendor/symfony/console/Helper/ProgressIndicator.php
+++ b/vendor/symfony/console/Helper/ProgressIndicator.php
@@ -20,6 +20,17 @@
*/
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 @@ public function __construct(OutputInterface $output, string $format = null, int
/**
* 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 @@ public function setMessage($message)
/**
* 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 @@ public function advance()
*
* @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 @@ public function finish($message)
/**
* 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 @@ public static function setPlaceholderFormatterDefinition($name, $callable)
}
/**
- * Gets the placeholder formatter for a given name.
- *
- * @param string $name The placeholder name (including the delimiter char like %)
+ * Gets the placeholder formatter for a given 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 @@ private static function initPlaceholderFormatters(): array
},
];
}
-
- 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 a4754b82..e236be92 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\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 @@
*/
class QuestionHelper extends Helper
{
+ /**
+ * @var resource|null
+ */
private $inputStream;
- private static $shell;
+
private static $stty = true;
private static $stdinIsInteractive;
@@ -122,9 +128,18 @@ private function doAsk(OutputInterface $output, Question $question)
}
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 @@ protected function writePrompt(OutputInterface $output, Question $question)
}
/**
- * @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 @@ protected function writeError(OutputInterface $output, \Exception $error)
*/
private function autocomplete(OutputInterface $output, Question $question, $inputStream, callable $autocomplete): string
{
+ $cursor = new Cursor($output, $inputStream);
+
$fullChoice = '';
$ret = '';
@@ -248,6 +263,9 @@ private function autocomplete(OutputInterface $output, Question $question, $inpu
$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 @@ private function autocomplete(OutputInterface $output, Question $question, $inpu
// 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 @@ function ($match) use ($ret) {
}
}
- // 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 @@ private function getHiddenResponse(OutputInterface $output, $inputStream, bool $
$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 @@ private function isInteractiveInput($inputStream): bool
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 @@ private function resetIOCodepage(int $cp, $input)
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 ace5e186..01f94aba 100644
--- a/vendor/symfony/console/Helper/SymfonyQuestionHelper.php
+++ b/vendor/symfony/console/Helper/SymfonyQuestionHelper.php
@@ -33,6 +33,10 @@ protected function writePrompt(OutputInterface $output, Question $question)
$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 @@ protected function writeError(OutputInterface $output, \Exception $error)
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 f068f02f..5c3447ab 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 @@ public function __construct(OutputInterface $output)
/**
* 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 @@ public static function setStyleDefinition($name, TableStyle $style)
/**
* 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 @@ public function getStyle()
/**
* 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 @@ public function setColumnStyle($columnIndex, $name)
*
* 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 @@ public function getColumnStyle($columnIndex)
/**
* 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 @@ public function setColumnWidths(array $widths)
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 @@ public function setColumnMaxWidth(int $columnIndex, int $width): self
return $this;
}
+ /**
+ * @return $this
+ */
public function setHeaders(array $headers)
{
$headers = array_values($headers);
@@ -257,6 +251,9 @@ public function setRows(array $rows)
return $this->addRows($rows);
}
+ /**
+ * @return $this
+ */
public function addRows(array $rows)
{
foreach ($rows as $row) {
@@ -266,6 +263,9 @@ public function addRows(array $rows)
return $this;
}
+ /**
+ * @return $this
+ */
public function addRow($row)
{
if ($row instanceof TableSeparator) {
@@ -285,6 +285,8 @@ public function addRow($row)
/**
* Adds a row to the table, and re-renders the table.
+ *
+ * @return $this
*/
public function appendRow($row): self
{
@@ -302,6 +304,9 @@ public function appendRow($row): self
return $this;
}
+ /**
+ * @return $this
+ */
public function setRow($column, array $row)
{
$this->rows[$column] = $row;
@@ -309,6 +314,9 @@ public function setRow($column, array $row)
return $this;
}
+ /**
+ * @return $this
+ */
public function setHeaderTitle(?string $title): self
{
$this->headerTitle = $title;
@@ -316,6 +324,9 @@ public function setHeaderTitle(?string $title): self
return $this;
}
+ /**
+ * @return $this
+ */
public function setFooterTitle(?string $title): self
{
$this->footerTitle = $title;
@@ -323,6 +334,9 @@ public function setFooterTitle(?string $title): self
return $this;
}
+ /**
+ * @return $this
+ */
public function setHorizontal(bool $horizontal = true): self
{
$this->horizontal = $horizontal;
@@ -466,11 +480,11 @@ private function renderRowSeparator(int $type = self::SEPARATOR_MID, string $tit
}
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).'...');
}
@@ -543,10 +557,33 @@ private function renderCell(array $row, int $column, string $cellFormat): string
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));
}
/**
@@ -578,7 +615,7 @@ private function buildTableRows(array $rows): TableRows
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")) {
@@ -642,7 +679,7 @@ private function fillNextRows(array $rows, int $line): array
$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)));
+ 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;
@@ -651,7 +688,7 @@ private function fillNextRows(array $rows, int $line): array
$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]);
}
@@ -659,7 +696,7 @@ private function fillNextRows(array $rows, int $line): array
$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;
}
@@ -766,9 +803,9 @@ private function calculateColumnsWidth(iterable $groups)
foreach ($row as $i => $cell) {
if ($cell instanceof TableCell) {
$textContent = Helper::removeDecoration($this->output->getFormatter(), $cell);
- $textLength = Helper::strlen($textContent);
+ $textLength = Helper::width($textContent);
if ($textLength > 0) {
- $contentColumns = str_split($textContent, ceil($textLength / $cell->getColspan()));
+ $contentColumns = mb_str_split($textContent, ceil($textLength / $cell->getColspan()));
foreach ($contentColumns as $position => $content) {
$row[$i + $position] = $content;
}
@@ -780,13 +817,13 @@ private function calculateColumnsWidth(iterable $groups)
}
}
- $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
@@ -795,7 +832,7 @@ private function getCellWidth(array $row, int $column): int
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;
@@ -813,6 +850,9 @@ private function cleanup()
$this->numberOfColumns = null;
}
+ /**
+ * @return array
+ */
private static function initStyles(): array
{
$borderless = new TableStyle();
diff --git a/vendor/symfony/console/Helper/TableCell.php b/vendor/symfony/console/Helper/TableCell.php
index 5b6af4a9..1a7bc6ed 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 @@ public function __construct(string $value = '', array $options = [])
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 @@ public function getRowspan()
{
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 00000000..19cd0ffc
--- /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 16aabb3f..cbc07d29 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 a8df59b3..dfc41e6a 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 @@ public function getPaddingChar()
* ╚═══════════════╧══════════════════════════╧══════════════════╝
*
*
- * @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 @@ public function setHorizontalBorderChars(string $outside, string $inside = null)
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 @@ public function getHorizontalBorderChar()
* ╚═══════════════╧══════════════════════════╧══════════════════╝
*
*
- * @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 @@ public function setVerticalBorderChars(string $outside, string $inside = null):
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 @@ public function getBorderChars(): array
* @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 @@ public function setDefaultCrossingChar(string $char): self
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 @@ public function getCrossingChars(): array
/**
* 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 @@ public function getCellHeaderFormat()
/**
* 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 @@ public function getCellRowFormat()
/**
* 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 @@ public function getCellRowContentFormat()
/**
* 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 @@ public function getBorderFormat()
/**
* 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 @@ public function getHeaderTitleFormat(): string
return $this->headerTitleFormat;
}
+ /**
+ * @return $this
+ */
public function setHeaderTitleFormat(string $format): self
{
$this->headerTitleFormat = $format;
@@ -449,6 +364,9 @@ public function getFooterTitleFormat(): string
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 63f40f27..675b9ef5 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,18 +68,25 @@ protected function parse()
$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;
}
/**
@@ -168,11 +172,25 @@ private function parseArgument(string $token)
// unexpected argument
} else {
$all = $this->definition->getArguments();
+ $symfonyCommandName = null;
+ if (($inputArgument = $all[$key = array_key_first($all)] ?? null) && 'command' === $inputArgument->getName()) {
+ $symfonyCommandName = $this->arguments['command'] ?? null;
+ unset($all[$key]);
+ }
+
if (\count($all)) {
- throw new RuntimeException(sprintf('Too many arguments, expected arguments "%s".', implode('" "', array_keys($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(sprintf('No arguments expected, got "%s".', $token));
+ throw new RuntimeException($message);
}
}
@@ -198,7 +216,17 @@ private function addShortOption(string $shortcut, $value)
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 @@ public function getFirstArgument()
/**
* {@inheritdoc}
*/
- public function hasParameterOption($values, $onlyParams = false)
+ public function hasParameterOption($values, bool $onlyParams = false)
{
$values = (array) $values;
@@ -298,7 +326,7 @@ public function hasParameterOption($values, $onlyParams = false)
/**
* {@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 30bd2054..c6516148 100644
--- a/vendor/symfony/console/Input/ArrayInput.php
+++ b/vendor/symfony/console/Input/ArrayInput.php
@@ -53,7 +53,7 @@ public function getFirstArgument()
/**
* {@inheritdoc}
*/
- public function hasParameterOption($values, $onlyParams = false)
+ public function hasParameterOption($values, bool $onlyParams = false)
{
$values = (array) $values;
@@ -77,7 +77,7 @@ public function hasParameterOption($values, $onlyParams = false)
/**
* {@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 @@ private function addShortOption(string $shortcut, $value)
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 d7f29073..d37460ed 100644
--- a/vendor/symfony/console/Input/Input.php
+++ b/vendor/symfony/console/Input/Input.php
@@ -88,9 +88,9 @@ public function isInteractive()
/**
* {@inheritdoc}
*/
- public function setInteractive($interactive)
+ public function setInteractive(bool $interactive)
{
- $this->interactive = (bool) $interactive;
+ $this->interactive = $interactive;
}
/**
@@ -104,9 +104,9 @@ public function getArguments()
/**
* {@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 @@ public function getArgument($name)
/**
* {@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 @@ public function setArgument($name, $value)
/**
* {@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 @@ public function getOptions()
/**
* {@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 @@ public function getOption($name)
/**
* {@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 @@ public function setOption($name, $value)
/**
* {@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 accd4d0c..8a64f7ac 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 @@ public function __construct(string $name, int $mode = null, string $description
/**
* Returns the argument name.
*
- * @return string The argument name
+ * @return string
*/
public function getName()
{
@@ -120,7 +120,7 @@ public function getDefault()
/**
* 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 e2cd6d71..11f704f0 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 @@ public function setDefinition(array $definition)
*
* @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 @@ public function setArguments($arguments = [])
*
* @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 @@ public function addArgument(InputArgument $argument)
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 @@ public function addArgument(InputArgument $argument)
*
* @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 @@ public function getArgument($name)
*
* @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 @@ public function hasArgument($name)
/**
* Gets the array of InputArgument objects.
*
- * @return InputArgument[] An array of InputArgument objects
+ * @return InputArgument[]
*/
public function getArguments()
{
@@ -167,17 +168,17 @@ public function getArguments()
/**
* 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 @@ public function getArgumentDefaults()
*
* @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 @@ public function setOptions($options = [])
*
* @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 @@ public function addOption(InputOption $option)
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 @@ public function addOption(InputOption $option)
$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 @@ public function getOption($name)
* 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 @@ public function hasOption($name)
/**
* Gets the array of InputOption objects.
*
- * @return InputOption[] An array of InputOption objects
+ * @return InputOption[]
*/
public function getOptions()
{
@@ -292,23 +301,27 @@ public function getOptions()
/**
* 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));
}
@@ -343,13 +356,27 @@ public function shortcutToName(string $shortcut): string
}
/**
- * Gets the synopsis.
+ * Returns the InputOption name given a negation.
+ *
+ * @throws InvalidArgumentException When option given does not exist
*
- * @param bool $short Whether to return the short version (with options folded) or not
+ * @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.
*
- * @return string The synopsis
+ * @return string
*/
- public function getSynopsis($short = false)
+ public function getSynopsis(bool $short = false)
{
$elements = [];
@@ -368,7 +395,8 @@ public function getSynopsis($short = false)
}
$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 8efc6232..628b6037 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 @@ public function getFirstArgument();
* @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 @@ public function hasParameterOption($values, $onlyParams = false);
* @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 @@ public function getArguments();
/**
* 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 @@ public function getOptions();
/**
* 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 @@ public function isInteractive();
/**
* 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 c7729db2..2bec34fe 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 @@ public function __construct(string $name, $shortcut = null, int $mode = null, st
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 @@ public function __construct(string $name, $shortcut = null, int $mode = null, st
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 @@ public function __construct(string $name, $shortcut = null, int $mode = null, st
/**
* Returns the option shortcut.
*
- * @return string|null The shortcut
+ * @return string|null
*/
public function getShortcut()
{
@@ -114,7 +120,7 @@ public function getShortcut()
/**
* Returns the option name.
*
- * @return string The name
+ * @return string
*/
public function getName()
{
@@ -161,6 +167,11 @@ public function isArray()
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 @@ public function setDefault($default = null)
}
}
- $this->default = $this->acceptValue() ? $default : false;
+ $this->default = $this->acceptValue() || $this->isNegatable() ? $default : false;
}
/**
@@ -194,7 +205,7 @@ public function getDefault()
/**
* Returns the description text.
*
- * @return string The description text
+ * @return string
*/
public function getDescription()
{
@@ -211,6 +222,7 @@ public function equals(self $option)
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/LICENSE b/vendor/symfony/console/LICENSE
index 88bf75bb..0138f8f0 100644
--- a/vendor/symfony/console/LICENSE
+++ b/vendor/symfony/console/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/console/Output/BufferedOutput.php b/vendor/symfony/console/Output/BufferedOutput.php
index fefaac27..d37c6e32 100644
--- a/vendor/symfony/console/Output/BufferedOutput.php
+++ b/vendor/symfony/console/Output/BufferedOutput.php
@@ -34,7 +34,7 @@ public function fetch()
/**
* {@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 484fcbde..f19f9ebf 100644
--- a/vendor/symfony/console/Output/ConsoleOutput.php
+++ b/vendor/symfony/console/Output/ConsoleOutput.php
@@ -67,7 +67,7 @@ public function section(): ConsoleSectionOutput
/**
* {@inheritdoc}
*/
- public function setDecorated($decorated)
+ public function setDecorated(bool $decorated)
{
parent::setDecorated($decorated);
$this->stderr->setDecorated($decorated);
@@ -85,7 +85,7 @@ public function setFormatter(OutputFormatterInterface $formatter)
/**
* {@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 f4c2fa62..6b6635f5 100644
--- a/vendor/symfony/console/Output/ConsoleOutputInterface.php
+++ b/vendor/symfony/console/Output/ConsoleOutputInterface.php
@@ -16,8 +16,6 @@
* 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 c19edbf9..8f164975 100644
--- a/vendor/symfony/console/Output/ConsoleSectionOutput.php
+++ b/vendor/symfony/console/Output/ConsoleSectionOutput.php
@@ -92,7 +92,7 @@ public function addContent(string $input)
/**
* {@inheritdoc}
*/
- protected function doWrite($message, $newline)
+ protected function doWrite(string $message, bool $newline)
{
if (!$this->isDecorated()) {
parent::doWrite($message, $newline);
@@ -136,8 +136,8 @@ private function popStreamContentUntilCurrentSection(int $numberOfLinesToClearFr
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 218f285b..3bbe63ea 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 @@
*/
class NullOutput implements OutputInterface
{
+ private $formatter;
+
/**
* {@inheritdoc}
*/
@@ -37,14 +39,17 @@ public function setFormatter(OutputFormatterInterface $formatter)
*/
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 @@ public function isDecorated()
/**
* {@inheritdoc}
*/
- public function setVerbosity($level)
+ public function setVerbosity(int $level)
{
// do nothing
}
@@ -108,7 +113,7 @@ public function isDebug()
/**
* {@inheritdoc}
*/
- public function writeln($messages, $options = self::OUTPUT_NORMAL)
+ public function writeln($messages, int $options = self::OUTPUT_NORMAL)
{
// do nothing
}
@@ -116,7 +121,7 @@ public function writeln($messages, $options = self::OUTPUT_NORMAL)
/**
* {@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 fb838f05..d7c5fb2d 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 @@ public function getFormatter()
/**
* {@inheritdoc}
*/
- public function setDecorated($decorated)
+ public function setDecorated(bool $decorated)
{
$this->formatter->setDecorated($decorated);
}
@@ -79,9 +79,9 @@ public function isDecorated()
/**
* {@inheritdoc}
*/
- public function setVerbosity($level)
+ public function setVerbosity(int $level)
{
- $this->verbosity = (int) $level;
+ $this->verbosity = $level;
}
/**
@@ -127,7 +127,7 @@ public function isDebug()
/**
* {@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 @@ public function writeln($messages, $options = self::OUTPUT_NORMAL)
/**
* {@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 @@ public function write($messages, $newline = false, $options = self::OUTPUT_NORMA
/**
* 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 671d5bd7..55caab80 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 @@ public function write($messages, $newline = false, $options = 0);
* @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 9c224364..7f555182 100644
--- a/vendor/symfony/console/Output/StreamOutput.php
+++ b/vendor/symfony/console/Output/StreamOutput.php
@@ -57,7 +57,7 @@ public function __construct($stream, int $verbosity = self::VERBOSITY_NORMAL, bo
/**
* Gets the stream attached to this StreamOutput instance.
*
- * @return resource A stream resource
+ * @return resource
*/
public function getStream()
{
@@ -67,7 +67,7 @@ public function getStream()
/**
* {@inheritdoc}
*/
- protected function doWrite($message, $newline)
+ protected function doWrite(string $message, bool $newline)
{
if ($newline) {
$message .= \PHP_EOL;
@@ -110,16 +110,6 @@ protected function hasColorSupport()
|| '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 87c04a89..3f4d375f 100644
--- a/vendor/symfony/console/Output/TrimmedBufferOutput.php
+++ b/vendor/symfony/console/Output/TrimmedBufferOutput.php
@@ -50,7 +50,7 @@ public function fetch()
/**
* {@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 6247ca71..bf1f9048 100644
--- a/vendor/symfony/console/Question/ChoiceQuestion.php
+++ b/vendor/symfony/console/Question/ChoiceQuestion.php
@@ -58,11 +58,9 @@ public function getChoices()
*
* 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 @@ public function getPrompt()
/**
* 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 @@ public function setPrompt($prompt)
*
* 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 @@ private function getDefaultValidator(): callable
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 cc108018..3a73f04b 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 @@ public function getDefault()
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 @@ public function isHidden()
/**
* 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 @@ public function isHiddenFallback()
}
/**
- * 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 @@ public function getAutocompleterValues()
/**
* 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 @@ public function setAutocompleterValues($values)
$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 @@ public function getValidator()
*
* 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 @@ public function getNormalizer()
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 c89b4a1a..c4c12998 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 00000000..64b87ccf
--- /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 00000000..6bee24a4
--- /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 00000000..e93c1821
--- /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 14d2d60b..67a98ff0 100644
--- a/vendor/symfony/console/Style/OutputStyle.php
+++ b/vendor/symfony/console/Style/OutputStyle.php
@@ -33,17 +33,15 @@ public function __construct(OutputInterface $output)
/**
* {@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 @@ public function createProgressBar($max = 0)
/**
* {@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 @@ public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL)
/**
* {@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 @@ public function writeln($messages, $type = self::OUTPUT_NORMAL)
/**
* {@inheritdoc}
*/
- public function setVerbosity($level)
+ public function setVerbosity(int $level)
{
$this->output->setVerbosity($level);
}
@@ -83,7 +81,7 @@ public function getVerbosity()
/**
* {@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 3b5b8af5..38d23b77 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 @@ public function table(array $headers, array $rows);
/**
* 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 1c99a186..e3c5ac8e 100644
--- a/vendor/symfony/console/Style/SymfonyStyle.php
+++ b/vendor/symfony/console/Style/SymfonyStyle.php
@@ -21,6 +21,7 @@
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 @@ public function __construct(InputInterface $input, OutputInterface $output)
$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 @@ public function block($messages, $type = null, $style = null, $prefix = ' ', $pa
/**
* {@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 @@ public function title($message)
/**
* {@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 @@ public function note($message)
$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 @@ public function caution($message)
*/
public function table(array $headers, array $rows)
{
- $style = clone Table::getStyleDefinition('symfony-style-guide');
- $style->setCellHeaderFormat('%s');
-
- $table = new Table($this);
- $table->setHeaders($headers);
- $table->setRows($rows);
- $table->setStyle($style);
+ $this->createTable()
+ ->setHeaders($headers)
+ ->setRows($rows)
+ ->render()
+ ;
- $table->render();
$this->newLine();
}
@@ -198,16 +202,13 @@ public function table(array $headers, array $rows)
*/
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 @@ public function horizontalTable(array $headers, array $rows)
*/
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 @@ public function definitionList(...$list)
$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 @@ public function ask($question, $default = null, $validator = null)
/**
* {@inheritdoc}
*/
- public function askHidden($question, $validator = null)
+ public function askHidden(string $question, callable $validator = null)
{
$question = new Question($question);
@@ -283,7 +274,7 @@ public function askHidden($question, $validator = null)
/**
* {@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 @@ public function confirm($question, $default = true)
/**
* {@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 @@ public function choice($question, array $choices, $default = null)
/**
* {@inheritdoc}
*/
- public function progressStart($max = 0)
+ public function progressStart(int $max = 0)
{
$this->progressBar = $this->createProgressBar($max);
$this->progressBar->start();
@@ -313,7 +304,7 @@ public function progressStart($max = 0)
/**
* {@inheritdoc}
*/
- public function progressAdvance($step = 1)
+ public function progressAdvance(int $step = 1)
{
$this->getProgressBar()->advance($step);
}
@@ -331,7 +322,7 @@ public function progressFinish()
/**
* {@inheritdoc}
*/
- public function createProgressBar($max = 0)
+ public function createProgressBar(int $max = 0)
{
$progressBar = parent::createProgressBar($max);
@@ -344,6 +335,16 @@ public function createProgressBar($max = 0)
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 @@ public function askQuestion(Question $question)
/**
* {@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 @@ public function writeln($messages, $type = self::OUTPUT_NORMAL)
/**
* {@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 @@ public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL)
/**
* {@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 @@ public function getErrorStyle()
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) {
@@ -456,7 +466,7 @@ private function writeBuffer(string $message, bool $newLine, int $type): void
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 @@ private function createBlock(iterable $messages, string $type = null, string $st
$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 @@ private function createBlock(iterable $messages, string $type = null, string $st
}
$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 5e5a3c2f..b91e8afc 100644
--- a/vendor/symfony/console/Terminal.php
+++ b/vendor/symfony/console/Terminal.php
@@ -57,29 +57,26 @@ public function getHeight()
/**
* @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 @@ private static function readFromProcess(string $command): ?string
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 @@ private static function readFromProcess(string $command): ?string
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 ce4e5c18..3a262e81 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,12 +45,9 @@ public function __construct(Application $application)
* * 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 = [])
{
$prevShellVerbosity = getenv('SHELL_VERBOSITY');
diff --git a/vendor/symfony/console/Tester/CommandCompletionTester.php b/vendor/symfony/console/Tester/CommandCompletionTester.php
new file mode 100644
index 00000000..ade73275
--- /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 57efc9a6..6c15c25f 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 00000000..a4732423
--- /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 27d59855..f454bbf9 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 @@ public function getDisplay($normalize = false)
*
* @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 @@ public function getErrorOutput($normalize = false)
/**
* 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 @@ public function getInput()
/**
* 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 @@ public function getOutput()
/**
* 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 90cbd24f..4fa4964a 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/polyfill-ctype/Ctype.php b/vendor/symfony/polyfill-ctype/Ctype.php
new file mode 100644
index 00000000..ba75a2c9
--- /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 00000000..7536caea
--- /dev/null
+++ b/vendor/symfony/polyfill-ctype/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2018-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/polyfill-ctype/README.md b/vendor/symfony/polyfill-ctype/README.md
new file mode 100644
index 00000000..b144d03c
--- /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 00000000..d54524b3
--- /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 00000000..ab2f8611
--- /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 00000000..e5c978f1
--- /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.28-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 00000000..5373f168
--- /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 00000000..6e3afce6
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-grapheme/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2015-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/polyfill-intl-grapheme/README.md b/vendor/symfony/polyfill-intl-grapheme/README.md
new file mode 100644
index 00000000..f55d92c5
--- /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 00000000..a9ea03c7
--- /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 00000000..b8c07867
--- /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 00000000..c00d4e9e
--- /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.28-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 00000000..6e3afce6
--- /dev/null
+++ b/vendor/symfony/polyfill-intl-normalizer/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2015-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/polyfill-intl-normalizer/Normalizer.php b/vendor/symfony/polyfill-intl-normalizer/Normalizer.php
new file mode 100644
index 00000000..81704ab3
--- /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 00000000..b9b762e8
--- /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 00000000..0fdfc890
--- /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 00000000..5a3e8e09
--- /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 00000000..ec90f36e
--- /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 00000000..15749028
--- /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 00000000..3608e5c0
--- /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 00000000..e36d1a94
--- /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 00000000..2c4de2c8
--- /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.28-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 00000000..13567c7b
--- /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 00000000..80b8326a
--- /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 00000000..626d8c1b
--- /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 00000000..53af3640
--- /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 00000000..8ab92094
--- /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 00000000..36197865
--- /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 00000000..6aa586bc
--- /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 00000000..77cb091f
--- /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 00000000..5d16977e
--- /dev/null
+++ b/vendor/symfony/string/Inflector/EnglishInflector.php
@@ -0,0 +1,526 @@
+
+ *
+ * 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'],
+
+ // statuses (status)
+ ['sesutats', 8, true, true, 'status'],
+
+ // 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']],
+
+ // status (status)
+ ['sutats', 6, true, true, 'status'],
+
+ // 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'],
+
+ // status (status)
+ ['sutats', 6, true, true, ['status', 'statuses']],
+
+ // 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 00000000..612c8f2e
--- /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 00000000..67f28340
--- /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 00000000..f37c76b5
--- /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 00000000..9c7a9c58
--- /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 00000000..9c7e1e19
--- /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 00000000..5a647e67
--- /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 00000000..5aecfeb5
--- /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 00000000..c679ed93
--- /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 00000000..9b906c6f
--- /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 00000000..2b88fd52
--- /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"
+}